mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-14 08:30:58 +00:00
Lunatic: more complete gameactor(), misc. translator tweaks.
git-svn-id: https://svn.eduke32.com/eduke32@3315 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
48c47af5dc
commit
4ea9f799b1
8 changed files with 147 additions and 32 deletions
|
@ -82,6 +82,9 @@ struct action {
|
||||||
struct move {
|
struct move {
|
||||||
int16_t hvel, vvel;
|
int16_t hvel, vvel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct { int32_t id; struct move mv; } con_move_t;
|
||||||
|
typedef struct { int32_t id; struct action ac; } con_action_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -4016,6 +4016,20 @@ int32_t A_InsertSprite(int32_t whatsect,int32_t s_x,int32_t s_y,int32_t s_z,int3
|
||||||
#endif
|
#endif
|
||||||
s->hitag = *(g_tile[s_pn].execPtr+3);
|
s->hitag = *(g_tile[s_pn].execPtr+3);
|
||||||
}
|
}
|
||||||
|
#ifdef LUNATIC
|
||||||
|
else if (El_HaveActor(s_pn))
|
||||||
|
{
|
||||||
|
// ^^^ C-CON takes precedence for now.
|
||||||
|
const el_actor_t *a = &g_elActors[s_pn];
|
||||||
|
|
||||||
|
s->extra = a->strength;
|
||||||
|
s->hitag = a->movflags;
|
||||||
|
T5 = a->act.id;
|
||||||
|
T2 = a->mov.id;
|
||||||
|
Bmemcpy(&actor[i].ac, &a->act.ac, sizeof(struct action));
|
||||||
|
Bmemcpy(&actor[i].mv, &a->mov.mv, sizeof(struct move));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (show2dsector[SECT>>3]&(1<<(SECT&7))) show2dsprite[i>>3] |= (1<<(i&7));
|
if (show2dsector[SECT>>3]&(1<<(SECT&7))) show2dsprite[i>>3] |= (1<<(i&7));
|
||||||
else show2dsprite[i>>3] &= ~(1<<(i&7));
|
else show2dsprite[i>>3] &= ~(1<<(i&7));
|
||||||
|
|
|
@ -25,7 +25,11 @@ module(...)
|
||||||
|
|
||||||
|
|
||||||
local lastid = { action=0, move=0, ai=0 }
|
local lastid = { action=0, move=0, ai=0 }
|
||||||
local def = { action={}, move={}, ai={} }
|
local def = {
|
||||||
|
action = {NO=ffi.new("con_action_t")},
|
||||||
|
move = {NO=ffi.new("con_move_t")},
|
||||||
|
ai = {NO=ffi.new("con_ai_t")},
|
||||||
|
}
|
||||||
|
|
||||||
local function forbidden() error("newindex forbidden", 2) end
|
local function forbidden() error("newindex forbidden", 2) end
|
||||||
|
|
||||||
|
|
|
@ -985,9 +985,57 @@ G_._VERSION = _VERSION
|
||||||
|
|
||||||
G_._G = G_
|
G_._G = G_
|
||||||
|
|
||||||
|
local gameactor_internal = gameactor_internal -- included in lunatic.c
|
||||||
|
-- gameactor(tilenum [, strength [, act [, mov [, movflags]]]], actor_func)
|
||||||
|
local function our_gameactor(tilenum, ...)
|
||||||
|
local args = {...}
|
||||||
|
if (type(tilenum) ~= "number") then
|
||||||
|
error("invalid argument #1 to gameactor: must be a number", 2)
|
||||||
|
end
|
||||||
|
if (tilenum >= ffiC.MAXTILES+0ULL) then
|
||||||
|
error("invalid argument #1 to gameactor: must be a tile number (0 .. MAXTILES-1)", 2)
|
||||||
|
end
|
||||||
|
if (#args == 0) then
|
||||||
|
error("invalid call to gameactor: must have at least two arguments (tilenum, func)", 2)
|
||||||
|
end
|
||||||
|
if (type(args[#args]) ~= "function") then
|
||||||
|
error("invalid last argument to gameactor: must be a function", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local strength = (#args >= 2) and args[1] or 0
|
||||||
|
if (type(strength) ~= "number") then
|
||||||
|
error("invalid 'strength' argument to gameactor: must be a number", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: literal number action other than 0?
|
||||||
|
local act = (#args >= 3) and args[2] or "NO"
|
||||||
|
if (type(act)=="string") then
|
||||||
|
act = AC[act]
|
||||||
|
end
|
||||||
|
if (not ffi.istype(con_action_ct, act)) then
|
||||||
|
error("invalid 'act' argument to gameactor: must be a string or action", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: literal number move other than 0?
|
||||||
|
local mov = (#args >= 4) and args[3] or "NO"
|
||||||
|
if (type(mov)=="string") then
|
||||||
|
mov = MV[mov]
|
||||||
|
end
|
||||||
|
if (not ffi.istype(con_move_ct, mov)) then
|
||||||
|
error("invalid 'mov' argument to gameactor: must be a string or move", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local movflags = (#args >= 5) and args[4] or 0
|
||||||
|
if (type(movflags) ~= "number") then
|
||||||
|
error("invalid 'movflags' argument to gameactor: must be a number", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
gameactor_internal(tilenum, strength, act, mov, movflags, args[#args])
|
||||||
|
end
|
||||||
|
|
||||||
--- non-default data and functions
|
--- non-default data and functions
|
||||||
G_.gameevent = gameevent -- included in lunatic.c
|
G_.gameevent = gameevent -- included in lunatic.c
|
||||||
G_.gameactor = gameactor -- included in lunatic.c
|
G_.gameactor = our_gameactor
|
||||||
G_.player = player -- from above
|
G_.player = player -- from above
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ local pairs = pairs
|
||||||
local pcall = pcall
|
local pcall = pcall
|
||||||
local print = print
|
local print = print
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
|
local tostring = tostring
|
||||||
local type = type
|
local type = type
|
||||||
|
|
||||||
if (string.dump) then
|
if (string.dump) then
|
||||||
|
@ -24,7 +25,7 @@ if (string.dump) then
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
module(...)
|
module("lunacon")
|
||||||
|
|
||||||
|
|
||||||
-- I think that the "too many pending calls/choices" is unavoidable in general.
|
-- I think that the "too many pending calls/choices" is unavoidable in general.
|
||||||
|
@ -107,11 +108,26 @@ local function addcodef(fmt, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function on_actor_end(usertype, tsamm, codetab)
|
local function on_actor_end(usertype, tsamm, codetab)
|
||||||
-- TODO: strength, action, move, moveflags
|
|
||||||
local tilenum = tsamm[1]
|
local tilenum = tsamm[1]
|
||||||
|
|
||||||
-- usertype is non-nil only for 'useractor'
|
local str = ""
|
||||||
addcodef("gameactor(%d, function(_aci, _pli, _dist)", tilenum)
|
for i=2,math.min(#tsamm,4) do
|
||||||
|
if ((i==3 or i==4) and tsamm[i]=="0") then
|
||||||
|
-- HACK, gameactor() currently doesn't support literals
|
||||||
|
tsamm[i] = "'NO'"
|
||||||
|
end
|
||||||
|
str = str .. tostring(tsamm[i])..","
|
||||||
|
end
|
||||||
|
if (#tsamm==5) then
|
||||||
|
local flags = 0
|
||||||
|
for i=5,#tsamm do
|
||||||
|
flags = bit.bor(flags, tsamm[i])
|
||||||
|
end
|
||||||
|
str = str .. flags..","
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: usertype (is non-nil only for 'useractor')
|
||||||
|
addcodef("gameactor(%d,%sfunction(_aci, _pli, _dist)", tilenum, str)
|
||||||
assert(type(codetab)=="table")
|
assert(type(codetab)=="table")
|
||||||
g_actor_code[tilenum] = codetab
|
g_actor_code[tilenum] = codetab
|
||||||
|
|
||||||
|
@ -121,7 +137,7 @@ end
|
||||||
|
|
||||||
local function on_state_end(statename, codetab)
|
local function on_state_end(statename, codetab)
|
||||||
-- TODO: mangle names, make them accessible from other translation units
|
-- TODO: mangle names, make them accessible from other translation units
|
||||||
addcodef("local function %s()", statename)
|
addcodef("local function %s(_aci, _pli, _dist)", statename)
|
||||||
assert(type(codetab)=="table")
|
assert(type(codetab)=="table")
|
||||||
addcode(codetab)
|
addcode(codetab)
|
||||||
addcode("end")
|
addcode("end")
|
||||||
|
@ -732,7 +748,7 @@ local Ci = {
|
||||||
/ "_con.longjmp()", -- TODO: test with code from Wiki "return" entry
|
/ "_con.longjmp()", -- TODO: test with code from Wiki "return" entry
|
||||||
|
|
||||||
state = cmd(I)
|
state = cmd(I)
|
||||||
/ "%1()", -- TODO: mangle names
|
/ "%1(_aci, _pli, _dist)", -- TODO: mangle names
|
||||||
|
|
||||||
--- 1. get*, set*
|
--- 1. get*, set*
|
||||||
getactor = getstructcmd,
|
getactor = getstructcmd,
|
||||||
|
@ -930,7 +946,8 @@ local Ci = {
|
||||||
insertspriteq = cmd(),
|
insertspriteq = cmd(),
|
||||||
killit = cmd() -- NLCF
|
killit = cmd() -- NLCF
|
||||||
/ "_con.killit()",
|
/ "_con.killit()",
|
||||||
mikesnd = cmd(),
|
mikesnd = cmd()
|
||||||
|
/ "", -- TODO
|
||||||
nullop = cmd()
|
nullop = cmd()
|
||||||
/ "", -- NOTE: really generate no code
|
/ "", -- NOTE: really generate no code
|
||||||
pkick = cmd()
|
pkick = cmd()
|
||||||
|
@ -1095,9 +1112,9 @@ local Cif = {
|
||||||
ifrnd = cmd(D)
|
ifrnd = cmd(D)
|
||||||
/ "_con.rnd(%1)",
|
/ "_con.rnd(%1)",
|
||||||
ifpdistl = cmd(D)
|
ifpdistl = cmd(D)
|
||||||
/ "_dist<%1", -- TODO: maybe set actor[].timetosleep afterwards
|
/ "_dist<%1", -- TODO: conditionally set actor[].timetosleep afterwards
|
||||||
ifpdistg = cmd(D)
|
ifpdistg = cmd(D)
|
||||||
/ "_dist>%1", -- TODO: maybe set actor[].timetosleep afterwards
|
/ "_dist>%1", -- TODO: conditionally set actor[].timetosleep afterwards
|
||||||
ifactioncount = cmd(D)
|
ifactioncount = cmd(D)
|
||||||
/ ACS":get_acount()==%1",
|
/ ACS":get_acount()==%1",
|
||||||
ifcount = cmd(D)
|
ifcount = cmd(D)
|
||||||
|
@ -1160,11 +1177,12 @@ local Cif = {
|
||||||
ifoutside = cmd()
|
ifoutside = cmd()
|
||||||
/ format("_bit.band(sector[%s].ceilingstat,1)~=0", SPS".sectnum"),
|
/ format("_bit.band(sector[%s].ceilingstat,1)~=0", SPS".sectnum"),
|
||||||
ifonwater = cmd()
|
ifonwater = cmd()
|
||||||
/ format("sectnum[%s].lotag==1 and _math.abs(%s-sector[%s].floorz)<32*256",
|
/ format("sector[%s].lotag==1 and _math.abs(%s-sector[%s].floorz)<32*256",
|
||||||
SPS".sectnum", SPS".z", SPS".sectnum"),
|
SPS".sectnum", SPS".z", SPS".sectnum"),
|
||||||
ifnotmoving = cmd()
|
ifnotmoving = cmd()
|
||||||
/ "_bit.band(actor[_aci].movflag,49152)>16384",
|
/ "_bit.band(actor[_aci].movflag,49152)>16384",
|
||||||
ifnosounds = cmd(),
|
ifnosounds = cmd()
|
||||||
|
/ "false",
|
||||||
ifmultiplayer = cmd()
|
ifmultiplayer = cmd()
|
||||||
/ "false", -- TODO?
|
/ "false", -- TODO?
|
||||||
ifinwater = cmd()
|
ifinwater = cmd()
|
||||||
|
@ -1182,7 +1200,7 @@ local Cif = {
|
||||||
ifclient = cmd(),
|
ifclient = cmd(),
|
||||||
ifcanshoottarget = cmd()
|
ifcanshoottarget = cmd()
|
||||||
/ "_con._canshoottarget(_dist,_aci)",
|
/ "_con._canshoottarget(_dist,_aci)",
|
||||||
ifcanseetarget = cmd() -- TODO: maybe set timetosleep afterwards
|
ifcanseetarget = cmd() -- TODO: conditionally set timetosleep afterwards
|
||||||
/ format("_con._canseetarget(%s,%s)", SPS"", PLS""),
|
/ format("_con._canseetarget(%s,%s)", SPS"", PLS""),
|
||||||
ifcansee = cmd() * #sp1
|
ifcansee = cmd() * #sp1
|
||||||
/ format("_con._cansee(_aci,%s)", PLS""),
|
/ format("_con._cansee(_aci,%s)", PLS""),
|
||||||
|
@ -1576,7 +1594,10 @@ end
|
||||||
---=== EXPORTED FUNCTIONS ===---
|
---=== EXPORTED FUNCTIONS ===---
|
||||||
|
|
||||||
local function new_initial_perfile_codetab()
|
local function new_initial_perfile_codetab()
|
||||||
return { "local _con=require'con'; local _bit=require'bit'" }
|
return {
|
||||||
|
"local _con, _bit, _math = require'con', require'bit', require'math';",
|
||||||
|
"local sector, sprite, actor, player = sector, sprite, actor, player;"
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function parse(contents) -- local
|
function parse(contents) -- local
|
||||||
|
@ -1713,7 +1734,7 @@ if (string.dump) then
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
local file = require("io").stdout
|
local file = require("io").stderr
|
||||||
for filename,codetab in pairs(g_file_code) do
|
for filename,codetab in pairs(g_file_code) do
|
||||||
file:write(format("-- GENERATED CODE for \"%s\":\n", filename))
|
file:write(format("-- GENERATED CODE for \"%s\":\n", filename))
|
||||||
file:write(table.concat(flatten_codetab(codetab), "\n"))
|
file:write(table.concat(flatten_codetab(codetab), "\n"))
|
||||||
|
@ -1721,7 +1742,4 @@ if (string.dump) then
|
||||||
end
|
end
|
||||||
--]]
|
--]]
|
||||||
end
|
end
|
||||||
else
|
|
||||||
--- embedded
|
|
||||||
return { parse=parse }
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,7 @@ L_State g_ElState;
|
||||||
uint8_t g_elEvents[MAXEVENTS];
|
uint8_t g_elEvents[MAXEVENTS];
|
||||||
|
|
||||||
// same thing for actors:
|
// same thing for actors:
|
||||||
uint8_t g_elActors[MAXTILES];
|
el_actor_t g_elActors[MAXTILES];
|
||||||
|
|
||||||
// for timing events and actors
|
// for timing events and actors
|
||||||
uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
|
uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
|
||||||
|
@ -116,7 +116,7 @@ static void El_StateSetup(lua_State *L)
|
||||||
lua_pushcfunction(L, SetEvent_luacf);
|
lua_pushcfunction(L, SetEvent_luacf);
|
||||||
lua_setglobal(L, "gameevent");
|
lua_setglobal(L, "gameevent");
|
||||||
lua_pushcfunction(L, SetActor_luacf);
|
lua_pushcfunction(L, SetActor_luacf);
|
||||||
lua_setglobal(L, "gameactor");
|
lua_setglobal(L, "gameactor_internal");
|
||||||
|
|
||||||
Bassert(lua_gettop(L)==0);
|
Bassert(lua_gettop(L)==0);
|
||||||
}
|
}
|
||||||
|
@ -152,19 +152,35 @@ static int32_t SetEvent_luacf(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gameactor(<actortile>, lua_function)
|
// gameactor(actortile, strength, act, mov, movflags, lua_function)
|
||||||
static int32_t SetActor_luacf(lua_State *L)
|
static int32_t SetActor_luacf(lua_State *L)
|
||||||
{
|
{
|
||||||
int32_t actortile;
|
int32_t actortile, strength, movflags;
|
||||||
|
const con_action_t *act;
|
||||||
|
const con_move_t *mov;
|
||||||
|
|
||||||
if (lua_gettop(L) != 2)
|
el_actor_t *a;
|
||||||
luaL_error(L, "gameactor: must pass exactly two arguments");
|
|
||||||
|
Bassert(lua_gettop(L) == 6);
|
||||||
|
|
||||||
actortile = luaL_checkint(L, 1);
|
actortile = luaL_checkint(L, 1);
|
||||||
|
Bassert((unsigned)actortile < MAXTILES);
|
||||||
|
|
||||||
luaL_argcheck(L, (unsigned)actortile < MAXTILES, 1, "must be an tile number (0 .. MAXTILES-1)");
|
strength = luaL_checkint(L, 2);
|
||||||
L_CheckAndRegisterFunction(L, &g_elActors[actortile]);
|
movflags = luaL_checkint(L, 5);
|
||||||
g_elActors[actortile] = 1;
|
|
||||||
|
act = lua_topointer(L, 3);
|
||||||
|
mov = lua_topointer(L, 4);
|
||||||
|
|
||||||
|
a = &g_elActors[actortile];
|
||||||
|
L_CheckAndRegisterFunction(L, a);
|
||||||
|
a->haveit = 1;
|
||||||
|
|
||||||
|
a->strength = strength;
|
||||||
|
a->movflags = movflags;
|
||||||
|
|
||||||
|
Bmemcpy(&a->act, act, sizeof(con_action_t));
|
||||||
|
Bmemcpy(&a->mov, mov, sizeof(con_move_t));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,18 @@
|
||||||
|
|
||||||
extern L_State g_ElState;
|
extern L_State g_ElState;
|
||||||
|
|
||||||
|
// actor initialization data
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
con_move_t mov;
|
||||||
|
int16_t movflags;
|
||||||
|
int16_t strength;
|
||||||
|
con_action_t act;
|
||||||
|
uint8_t haveit; // shouldn't be used directly
|
||||||
|
} el_actor_t;
|
||||||
|
|
||||||
extern uint8_t g_elEvents[MAXEVENTS]; // shouldn't be used directly
|
extern uint8_t g_elEvents[MAXEVENTS]; // shouldn't be used directly
|
||||||
extern uint8_t g_elActors[MAXTILES]; // shouldn't be used directly
|
extern el_actor_t g_elActors[MAXTILES];
|
||||||
|
|
||||||
extern uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
|
extern uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
|
||||||
extern double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES];
|
extern double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES];
|
||||||
|
@ -26,6 +35,6 @@ int32_t El_CallEvent(L_State *estate, int32_t eventidx, int32_t iActor, int32_t
|
||||||
int32_t El_CallActor(L_State *estate, int32_t actortile, int32_t iActor, int32_t iPlayer, int32_t lDist);
|
int32_t El_CallActor(L_State *estate, int32_t actortile, int32_t iActor, int32_t iPlayer, int32_t lDist);
|
||||||
|
|
||||||
static inline int32_t El_HaveEvent(int32_t eventidx) { return g_elEvents[eventidx]!=0; }
|
static inline int32_t El_HaveEvent(int32_t eventidx) { return g_elEvents[eventidx]!=0; }
|
||||||
static inline int32_t El_HaveActor(int32_t actortile) { return g_elActors[actortile]!=0; }
|
static inline int32_t El_HaveActor(int32_t actortile) { return g_elActors[actortile].haveit!=0; }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -176,7 +176,7 @@ checkfail('local i = actor[0].t_data[15]', "has no member named 't_data'")
|
||||||
-- no pointer arithmetic!
|
-- no pointer arithmetic!
|
||||||
checkfail('local spr = sprite[0]; local x=spr+1', "attempt to perform arithmetic on")
|
checkfail('local spr = sprite[0]; local x=spr+1', "attempt to perform arithmetic on")
|
||||||
|
|
||||||
checkfail('gameactor(1680, 0)', "bad argument #3 to 'gameactor' (function expected, got number)")
|
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")
|
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!
|
-- the cdata returned by player[] can't be made into a pointer!
|
||||||
|
@ -236,6 +236,7 @@ local hs = stat.new()
|
||||||
|
|
||||||
local con = require("con")
|
local con = require("con")
|
||||||
local AC, MV = con.AC, con.MV
|
local AC, MV = con.AC, con.MV
|
||||||
|
con.action("TROOPSTAND",0,1,5,1,1)
|
||||||
con.action("TROOPFLINTCH", 50, 1, 1, 1, 6)
|
con.action("TROOPFLINTCH", 50, 1, 1, 1, 6)
|
||||||
con.move("SHRUNKVELS", 32)
|
con.move("SHRUNKVELS", 32)
|
||||||
con.ai("AITEMP", AC.TROOPFLINTCH, MV.SHRUNKVELS, 0) -- TODO: test
|
con.ai("AITEMP", AC.TROOPFLINTCH, MV.SHRUNKVELS, 0) -- TODO: test
|
||||||
|
@ -245,7 +246,9 @@ con.ai("AITEMP", AC.TROOPFLINTCH, MV.SHRUNKVELS, 0) -- TODO: test
|
||||||
-- Or will we allow only one definition per label ever?
|
-- Or will we allow only one definition per label ever?
|
||||||
con.ai("AITEMP", "TROOPFLINTCH", "SHRUNKVELS", 0)
|
con.ai("AITEMP", "TROOPFLINTCH", "SHRUNKVELS", 0)
|
||||||
|
|
||||||
gameactor(1680, -- LIZTROOP
|
local TROOPSTRENGTH = 30
|
||||||
|
|
||||||
|
gameactor(1680, TROOPSTRENGTH, "TROOPSTAND", -- LIZTROOP
|
||||||
function(i, playeri, dist)
|
function(i, playeri, dist)
|
||||||
sprite[i].pal = math.random(32)
|
sprite[i].pal = math.random(32)
|
||||||
-- sprite[i].ang = bit.band(sprite[i].ang-20, 2047)
|
-- sprite[i].ang = bit.band(sprite[i].ang-20, 2047)
|
||||||
|
|
Loading…
Reference in a new issue