mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-11 10:40:47 +00:00
Lunatic: player method fadecol(), an improved palfrom.
Also, an external 'minitext' with optional shade and pal. args and documentation for ps:padecol(). git-svn-id: https://svn.eduke32.com/eduke32@3893 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
e8c9bf044f
commit
5db04f585e
9 changed files with 234 additions and 21 deletions
|
@ -98,9 +98,15 @@ function bcheck.top_level(funcname)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function bcheck.number(val)
|
function bcheck.number(val, errlev)
|
||||||
if (type(val)~="number") then
|
if (type(val)~="number" or val~=val) then
|
||||||
error("invalid argument: must be a number", 3)
|
error("invalid argument: must be a non-NaN number", errlev or 3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function bcheck.type(val, typestr)
|
||||||
|
if (type(val)~=typestr) then
|
||||||
|
error("invalid argument: must be a "..typestr, 3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,7 @@ local check_tile_idx = bcheck.tile_idx
|
||||||
local check_sprite_idx = bcheck.sprite_idx
|
local check_sprite_idx = bcheck.sprite_idx
|
||||||
local check_player_idx = bcheck.player_idx
|
local check_player_idx = bcheck.player_idx
|
||||||
local check_sound_idx = bcheck.sound_idx
|
local check_sound_idx = bcheck.sound_idx
|
||||||
|
local check_type = bcheck.type
|
||||||
|
|
||||||
-- Will contain [<label>]=number mappings after CON translation.
|
-- Will contain [<label>]=number mappings after CON translation.
|
||||||
local D = { true }
|
local D = { true }
|
||||||
|
@ -793,7 +794,15 @@ function _switch(swtab, testval, aci,pli,dist)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- text rendering
|
--== Text rendering ==--
|
||||||
|
|
||||||
|
-- For external use. NOTE: <pal> comes before <shade>.
|
||||||
|
function minitext(x, y, str, pal, shade)
|
||||||
|
check_type(str, "string")
|
||||||
|
ffiC.minitext_(x, y, str, shade or 0, pal or 0, 2+8+16)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- For CON only.
|
||||||
function _minitext(x, y, qnum, shade, pal)
|
function _minitext(x, y, qnum, shade, pal)
|
||||||
local cstr = bcheck.quote_idx(qnum)
|
local cstr = bcheck.quote_idx(qnum)
|
||||||
ffiC.minitext_(x, y, cstr, shade, pal, 2+8+16)
|
ffiC.minitext_(x, y, cstr, shade, pal, 2+8+16)
|
||||||
|
|
|
@ -291,6 +291,7 @@ __attribute__((packed)) struct {
|
||||||
|
|
||||||
uint8_t palette;
|
uint8_t palette;
|
||||||
palette_t _pals;
|
palette_t _pals;
|
||||||
|
int8_t _palsfadespeed, _palsfadenext, _palsfadeprio, _padding2;
|
||||||
|
|
||||||
// NOTE: In C, the struct type has no name. We only have it here to define
|
// NOTE: In C, the struct type has no name. We only have it here to define
|
||||||
// a metatype later.
|
// a metatype later.
|
||||||
|
@ -1147,6 +1148,18 @@ local weaponaccess_mt = {
|
||||||
}
|
}
|
||||||
ffi.metatype("weaponaccess_t", weaponaccess_mt)
|
ffi.metatype("weaponaccess_t", weaponaccess_mt)
|
||||||
|
|
||||||
|
|
||||||
|
local function clamp(num, min, max)
|
||||||
|
return num < min and min
|
||||||
|
or num > max and max
|
||||||
|
or num
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clamp0to1(num)
|
||||||
|
check_number(num, 4)
|
||||||
|
return clamp(num, 0, 1)
|
||||||
|
end
|
||||||
|
|
||||||
local player_mt = {
|
local player_mt = {
|
||||||
__index = {
|
__index = {
|
||||||
-- CON-like addammo/addweapon, but without the non-local control flow
|
-- CON-like addammo/addweapon, but without the non-local control flow
|
||||||
|
@ -1188,9 +1201,64 @@ local player_mt = {
|
||||||
p.look_ang = n
|
p.look_ang = n
|
||||||
end,
|
end,
|
||||||
|
|
||||||
--- Not fully specified, off-limits to users. Might disappear, change
|
-- External, improved 'palfrom'.
|
||||||
--- signature, etc...
|
-- <speed>: possibly fractional speed of tint fading, in pals.f decrements per gametic.
|
||||||
-- TODO: need to think about external API: 0-255 based? 0-1 based?
|
-- XXX: exposes internals.
|
||||||
|
-- <prio>: a value from -128 to 127, higher ones trump lower or equal ones
|
||||||
|
fadecol = function(p, fadefrac, r, g, b, speed, prio)
|
||||||
|
-- Validate inargs: clamp f,r,g,b to [0 .. 1] first and multiply by
|
||||||
|
-- 63 for the internal handling.
|
||||||
|
fadefrac = clamp0to1(fadefrac)*63
|
||||||
|
-- NOTE: a fadefrac of now <1 is allowed, e.g. for clearing the tint.
|
||||||
|
r = clamp0to1(r)*63
|
||||||
|
g = clamp0to1(g)*63
|
||||||
|
b = clamp0to1(b)*63
|
||||||
|
|
||||||
|
if (speed ~= nil) then
|
||||||
|
check_number(speed)
|
||||||
|
-- Clamp to sensible values; the speed is stored in an int8_t
|
||||||
|
-- (see below).
|
||||||
|
speed = clamp(speed, 1/128, 127)
|
||||||
|
else
|
||||||
|
speed = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if (prio ~= nil) then
|
||||||
|
check_number(prio)
|
||||||
|
|
||||||
|
if (not (prio >= -128 and prio < 127)) then
|
||||||
|
error("invalid argument #6 (priority): must be in [-128 .. 127]", 2)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
prio = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if a currently active tint has higher priority.
|
||||||
|
if (p._pals.f > 0 and p._palsfadeprio > prio) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The passed tint can be applied now.
|
||||||
|
p:_palfrom(fadefrac, r, g, b)
|
||||||
|
p._palsfadeprio = prio
|
||||||
|
|
||||||
|
-- Calculate .palsfade{speed,next}
|
||||||
|
if (speed >= 1) then
|
||||||
|
-- Will round to the nearest integer ("banker's
|
||||||
|
-- rounding"). NOTE: This is not correct for all numbers, see
|
||||||
|
-- http://blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
|
||||||
|
p._palsfadespeed = speed + 0.5
|
||||||
|
p._palsfadenext = 0
|
||||||
|
else
|
||||||
|
-- NOTE: Values that round to 0 have are equivalent behavior to
|
||||||
|
-- passing a <speed> of 1.
|
||||||
|
local negspeedrecip = -((1/speed) + 0.5) -- [-128.5 .. 1/127+0.5]
|
||||||
|
p._palsfadespeed = negspeedrecip
|
||||||
|
p._palsfadenext = negspeedrecip
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
-- INTERNAL and CON-only.
|
||||||
_palfrom = function(p, f, r,g,b)
|
_palfrom = function(p, f, r,g,b)
|
||||||
local pals = p._pals
|
local pals = p._pals
|
||||||
pals.f = f
|
pals.f = f
|
||||||
|
|
|
@ -138,13 +138,13 @@ dot contained in it with a directory separator. Then, it looks for a file with
|
||||||
that base name suffixed with `.lua` in the EDuke32 search path (virtual file
|
that base name suffixed with `.lua` in the EDuke32 search path (virtual file
|
||||||
system, GRP, ZIP). Using directory separators directly is not allowed.
|
system, GRP, ZIP). Using directory separators directly is not allowed.
|
||||||
|
|
||||||
The loaded module is ``protected'' so that write accesses to its table yield
|
The loaded module is protected so that write accesses to its table yield
|
||||||
errors. Unlike Lua, our `module` does not return *true* when a module is
|
errors. Unlike Lua, our `module` does not return *true* when a module is
|
||||||
++require++d that has not yet finished loading (that is, the inclusion chain
|
++require++d that has not yet finished loading (that is, the inclusion chain
|
||||||
contains a loop). Instead, an error is raised.
|
contains a loop). Instead, an error is raised.
|
||||||
|
|
||||||
Issuing `require` for `'end_gamevars'` has a special meaning that is described
|
Issuing `require` for ```end_gamevars`'' has a special meaning that is described
|
||||||
below. A `require` for `'CON.DEFS'` returns a table mapping labels ++define++d from
|
below. A `require` for ```CON.DEFS`'' returns a table mapping labels ++define++d from
|
||||||
CON to their values, except for `NO`.
|
CON to their values, except for `NO`.
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,10 +157,10 @@ one call to `module`, which (if there is one) *must* be called at file scope.
|
||||||
|
|
||||||
===== Game variables
|
===== Game variables
|
||||||
|
|
||||||
Lunatic has a special mechanism to mark variables that represent some
|
Lunatic has a special mechanism to mark variables that represent persistent
|
||||||
``persistent'' state and whose values should be stored in savegames. If such
|
state and whose values should be stored in savegames. If such variables are
|
||||||
variables are desired, they must initialized between the `module` call in a Lua
|
desired, they must be initialized between the `module` call in a Lua file and a
|
||||||
file and a closing `require("end_gamevars")`. These variables may also be *`local`*.
|
closing `require("end_gamevars")`. These variables may also be *`local`*.
|
||||||
|
|
||||||
[icon="icons/din_w_collapse.png"]
|
[icon="icons/din_w_collapse.png"]
|
||||||
CAUTION: A game variable must contain a non-nil value at any time. Otherwise,
|
CAUTION: A game variable must contain a non-nil value at any time. Otherwise,
|
||||||
|
@ -728,6 +728,39 @@ Contains symbolic names of values applicable to <<gameactor,`gameactor`>>'s
|
||||||
|
|
||||||
===== `player`
|
===== `player`
|
||||||
|
|
||||||
|
===== `player` methods
|
||||||
|
|
||||||
|
`ps:fadecol(fadefrac, r, g, b [, speed [, prio]])`::
|
||||||
|
|
||||||
|
Initiates a tinting that linearly fades over time and is blended with the whole
|
||||||
|
screen contents whenever player `ps`'s view is displayed.footnote:[The behavior
|
||||||
|
is unspecified should more than one player's view be displayed at one time.]
|
||||||
|
The first argument `fadefrac` specifies the starting blending coefficient; `r`,
|
||||||
|
`g` and `b` specify the intensities of the red, green and blue color
|
||||||
|
components, respectively.
|
||||||
|
+
|
||||||
|
Both `fadefrac` and the component intensities are first clamped to the range
|
||||||
|
[0.0 .. 1.0]. The resulting values are interpreted as a fraction, 0.0 meaning
|
||||||
|
no blending/no color and 1.0 meaning full blending/full
|
||||||
|
color.footnote:[Currently, for implementation reasons, a value of 1.0 results
|
||||||
|
in only _almost_ full blending or presence of the specified color component.]
|
||||||
|
+
|
||||||
|
The fourth, optional argument `speed` controls the rate at which the tinting
|
||||||
|
diminishes. At a value of `1` (the default), a tint with a `fadefrac` of 0.5
|
||||||
|
finishes in approximately one second.
|
||||||
|
+
|
||||||
|
The last, optional argument `prio` must be an integer in the range [`-128`
|
||||||
|
.. `127`], the default being `0`. When a `fadecol` is issued in the presence of
|
||||||
|
another tint fading in progress, and the `prio` given by the arriving `fadecol`
|
||||||
|
is greater or equal than the `prio` of the ongoing one, the latter is canceled
|
||||||
|
and the arriving fading is initiated in its place. (There is no support for
|
||||||
|
tint fades that overlap in time.)
|
||||||
|
+
|
||||||
|
[icon="icons/din_w_crushing.png"]
|
||||||
|
CAUTION: If Lunatic code that uses `fadecol` is loaded together with CON code
|
||||||
|
that writes to the player's `pals` members directly at any point, the behavior
|
||||||
|
is undefined.
|
||||||
|
|
||||||
===== `projectile`
|
===== `projectile`
|
||||||
|
|
||||||
===== `g_tile`
|
===== `g_tile`
|
||||||
|
|
|
@ -528,6 +528,70 @@ gameevent
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local function testbit(num, b)
|
||||||
|
return bit.band(num,b)~=0 and 1 or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local FADE_SPEED = {
|
||||||
|
[gv.KNEE_WEAPON] = 1/2.5,
|
||||||
|
|
||||||
|
1/128,
|
||||||
|
1/5,
|
||||||
|
1/3,
|
||||||
|
1/2,
|
||||||
|
1, -- pipebomb: ~1 sec
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
127, -- freezer; such a fast fade is not visible, but it clears any
|
||||||
|
-- existing one (if of higher priority)
|
||||||
|
[gv.GROW_WEAPON] = 9.9, -- test banker's rouding -- should be like 10
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Test player[]:fadecol(), a better palfrom.
|
||||||
|
gameevent
|
||||||
|
{
|
||||||
|
"CHANGEWEAPON",
|
||||||
|
|
||||||
|
function (aci, pli)
|
||||||
|
local ps = player[pli]
|
||||||
|
local neww, curw = gv.g_RETURN, ps.curr_weapon
|
||||||
|
|
||||||
|
local r, g, b = testbit(neww, 1), testbit(neww, 2), testbit(neww, 4)
|
||||||
|
local speed = FADE_SPEED[neww] or 1
|
||||||
|
player[pli]:fadecol(0.5, r, g, b, speed, neww)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Time the above p:fadecol() test for verification of the <speed> argument.
|
||||||
|
local last_f, last_t = 0, 0
|
||||||
|
local last_secs = nil
|
||||||
|
gameevent
|
||||||
|
{
|
||||||
|
"DISPLAYREST",
|
||||||
|
|
||||||
|
function(aci, pli)
|
||||||
|
local ps = player[pli]
|
||||||
|
-- WARNING: This function uses INTERNAL interfaces.
|
||||||
|
local curf = ps._pals.f
|
||||||
|
if (curf > last_f) then
|
||||||
|
-- Starting a tint
|
||||||
|
last_secs = nil
|
||||||
|
last_f = curf
|
||||||
|
last_t = gv.getticks()
|
||||||
|
elseif (last_t > 0 and curf==0) then
|
||||||
|
-- Fade has ended
|
||||||
|
last_secs = (gv.getticks()-last_t)/1000
|
||||||
|
last_f, last_t = 0, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if (last_secs ~= nil) then
|
||||||
|
con.minitext(10, 10, string.format("Last fade time: %.03f s (%.03f gametics)",
|
||||||
|
last_secs, last_secs*30))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
printf("EVENT_INIT = %d", gv.EVENT_INIT) -- tests default defines
|
printf("EVENT_INIT = %d", gv.EVENT_INIT) -- tests default defines
|
||||||
|
|
||||||
local bittest = require "test.test_bitar"
|
local bittest = require "test.test_bitar"
|
||||||
|
|
|
@ -37,8 +37,6 @@ require "end_gamevars"
|
||||||
-- refer to locals defined prior to the gamevar section in it.
|
-- refer to locals defined prior to the gamevar section in it.
|
||||||
local tag = tag
|
local tag = tag
|
||||||
|
|
||||||
local Q = 1200
|
|
||||||
|
|
||||||
gameevent{"JUMP", actor.FLAGS.chain_beg,
|
gameevent{"JUMP", actor.FLAGS.chain_beg,
|
||||||
function(aci, pli)
|
function(aci, pli)
|
||||||
local ps = player[pli]
|
local ps = player[pli]
|
||||||
|
@ -85,8 +83,6 @@ gameevent
|
||||||
"DISPLAYREST",
|
"DISPLAYREST",
|
||||||
|
|
||||||
function()
|
function()
|
||||||
con._definequote(Q, string.format("jumped %d times", ournumjumps))
|
con.minitext(160, 10, string.format("jumped %d times", ournumjumps))
|
||||||
-- NOTE: uses INTERNAL interface, don't copy!
|
|
||||||
con._minitext(160, 10, Q, 0,0)
|
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
|
@ -4385,7 +4385,32 @@ void P_ProcessInput(int32_t snum)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->pals.f > 0)
|
if (p->pals.f > 0)
|
||||||
|
{
|
||||||
|
#ifndef LUNATIC
|
||||||
p->pals.f--;
|
p->pals.f--;
|
||||||
|
#else
|
||||||
|
if (p->palsfadespeed > 0)
|
||||||
|
{
|
||||||
|
// <palsfadespeed> is the tint fade speed is in
|
||||||
|
// decrements/P_ProcessInput() calls.
|
||||||
|
p->pals.f = max(p->pals.f - p->palsfadespeed, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// <palsfadespeed> is a negated count of how many times we
|
||||||
|
// (P_ProcessInput()) should be called before decrementing the tint
|
||||||
|
// fading by one. <palsfadenext> is the live counter.
|
||||||
|
if (p->palsfadenext < 0)
|
||||||
|
p->palsfadenext++;
|
||||||
|
|
||||||
|
if (p->palsfadenext == 0)
|
||||||
|
{
|
||||||
|
p->palsfadenext = p->palsfadespeed;
|
||||||
|
p->pals.f--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (p->fta > 0 && --p->fta == 0)
|
if (p->fta > 0 && --p->fta == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -230,6 +230,8 @@ typedef struct {
|
||||||
palette_t pals;
|
palette_t pals;
|
||||||
|
|
||||||
#ifdef LUNATIC
|
#ifdef LUNATIC
|
||||||
|
int8_t palsfadespeed, palsfadenext, palsfadeprio, padding2_;
|
||||||
|
|
||||||
// The player index. Always valid since we have no loose DukePlayer_t's
|
// The player index. Always valid since we have no loose DukePlayer_t's
|
||||||
// anywhere (like with spritetype_t): g_player[i].ps->wa.idx == i.
|
// anywhere (like with spritetype_t): g_player[i].ps->wa.idx == i.
|
||||||
struct { int32_t idx; } wa;
|
struct { int32_t idx; } wa;
|
||||||
|
|
|
@ -673,6 +673,14 @@ void P_RandomSpawnPoint(int32_t snum)
|
||||||
sprite[p->i].cstat = 1+256;
|
sprite[p->i].cstat = 1+256;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void P_ResetTintFade(DukePlayer_t *ps)
|
||||||
|
{
|
||||||
|
ps->pals.f = 0;
|
||||||
|
#ifdef LUNATIC
|
||||||
|
ps->palsfadeprio = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void P_ResetPlayer(int32_t snum)
|
void P_ResetPlayer(int32_t snum)
|
||||||
{
|
{
|
||||||
vec3_t tmpvect;
|
vec3_t tmpvect;
|
||||||
|
@ -708,7 +716,6 @@ void P_ResetPlayer(int32_t snum)
|
||||||
pl->wackedbyactor = -1;
|
pl->wackedbyactor = -1;
|
||||||
pl->inv_amount[GET_SHIELD] = g_startArmorAmount;
|
pl->inv_amount[GET_SHIELD] = g_startArmorAmount;
|
||||||
pl->dead_flag = 0;
|
pl->dead_flag = 0;
|
||||||
pl->pals.f = 0;
|
|
||||||
pl->footprintcount = 0;
|
pl->footprintcount = 0;
|
||||||
pl->weapreccnt = 0;
|
pl->weapreccnt = 0;
|
||||||
pl->fta = 0;
|
pl->fta = 0;
|
||||||
|
@ -718,6 +725,8 @@ void P_ResetPlayer(int32_t snum)
|
||||||
pl->runspeed = g_playerFriction;
|
pl->runspeed = g_playerFriction;
|
||||||
pl->falling_counter = 0;
|
pl->falling_counter = 0;
|
||||||
|
|
||||||
|
P_ResetTintFade(pl);
|
||||||
|
|
||||||
actor[pl->i].extra = -1;
|
actor[pl->i].extra = -1;
|
||||||
actor[pl->i].owner = pl->i;
|
actor[pl->i].owner = pl->i;
|
||||||
|
|
||||||
|
@ -897,7 +906,6 @@ static void resetprestat(int32_t snum,int32_t g)
|
||||||
|
|
||||||
p->hbomb_on = 0;
|
p->hbomb_on = 0;
|
||||||
p->cheat_phase = 0;
|
p->cheat_phase = 0;
|
||||||
p->pals.f = 0;
|
|
||||||
p->toggle_key_flag = 0;
|
p->toggle_key_flag = 0;
|
||||||
p->secret_rooms = 0;
|
p->secret_rooms = 0;
|
||||||
p->max_secret_rooms = 0;
|
p->max_secret_rooms = 0;
|
||||||
|
@ -906,6 +914,8 @@ static void resetprestat(int32_t snum,int32_t g)
|
||||||
p->lastrandomspot = 0;
|
p->lastrandomspot = 0;
|
||||||
p->weapon_pos = 6;
|
p->weapon_pos = 6;
|
||||||
|
|
||||||
|
P_ResetTintFade(p);
|
||||||
|
|
||||||
if ((PWEAPON(snum, p->curr_weapon, WorksLike) == PISTOL_WEAPON) &&
|
if ((PWEAPON(snum, p->curr_weapon, WorksLike) == PISTOL_WEAPON) &&
|
||||||
(PWEAPON(snum, p->curr_weapon, Reload) > PWEAPON(snum, p->curr_weapon, TotalTime)))
|
(PWEAPON(snum, p->curr_weapon, Reload) > PWEAPON(snum, p->curr_weapon, TotalTime)))
|
||||||
p->kickback_pic = PWEAPON(snum, p->curr_weapon, TotalTime);
|
p->kickback_pic = PWEAPON(snum, p->curr_weapon, TotalTime);
|
||||||
|
|
Loading…
Reference in a new issue