2014-03-15 16:59:03 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
2016-05-18 00:42:11 +00:00
// Copyright (C) 2014-2016 by John "JTE" Muniz.
2023-03-31 12:53:31 +00:00
// Copyright (C) 2014-2023 by Sonic Team Junior.
2014-03-15 16:59:03 +00:00
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file lua_hudlib.c
/// \brief custom HUD rendering library for Lua scripting
# include "doomdef.h"
2017-04-30 21:53:05 +00:00
# include "fastcmp.h"
2014-03-15 16:59:03 +00:00
# include "r_defs.h"
2014-11-12 00:55:07 +00:00
# include "r_local.h"
2014-03-15 16:59:03 +00:00
# include "st_stuff.h" // hudinfo[]
# include "g_game.h"
2016-01-31 21:53:14 +00:00
# include "i_video.h" // rendermode
2014-08-04 03:49:33 +00:00
# include "p_local.h" // camera_t
2016-01-31 21:53:14 +00:00
# include "screen.h" // screen width/height
2018-03-20 15:00:27 +00:00
# include "m_random.h" // m_random
2014-03-15 16:59:03 +00:00
# include "v_video.h"
# include "w_wad.h"
# include "z_zone.h"
2021-07-07 07:23:51 +00:00
# include "y_inter.h"
2014-03-15 16:59:03 +00:00
# include "lua_script.h"
# include "lua_libs.h"
# include "lua_hud.h"
2021-07-07 07:23:51 +00:00
# include "lua_hook.h"
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
# define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!");
2014-03-15 16:59:03 +00:00
boolean hud_running = false ;
static UINT8 hud_enabled [ ( hud_MAX / 8 ) + 1 ] ;
// must match enum hud in lua_hud.h
static const char * const hud_disable_options [ ] = {
" stagetitle " ,
" textspectator " ,
2020-12-29 20:36:15 +00:00
" crosshair " ,
2014-03-15 16:59:03 +00:00
" score " ,
" time " ,
" rings " ,
" lives " ,
2016-08-18 23:06:12 +00:00
" weaponrings " ,
" powerstones " ,
2019-12-16 20:58:00 +00:00
" teamscores " ,
2016-08-18 23:06:12 +00:00
2014-03-15 16:59:03 +00:00
" nightslink " ,
" nightsdrill " ,
" nightsrings " ,
" nightsscore " ,
" nightstime " ,
" nightsrecords " ,
" rankings " ,
" coopemeralds " ,
" tokens " ,
" tabemblems " ,
2019-12-18 21:09:56 +00:00
" intermissiontally " ,
2020-12-17 08:30:57 +00:00
" intermissiontitletext " ,
2019-12-18 21:09:56 +00:00
" intermissionmessages " ,
2020-12-14 07:23:57 +00:00
" intermissionemeralds " ,
2014-03-15 16:59:03 +00:00
NULL } ;
enum hudinfo {
hudinfo_x = 0 ,
2018-03-19 23:08:51 +00:00
hudinfo_y ,
hudinfo_f
2014-03-15 16:59:03 +00:00
} ;
static const char * const hudinfo_opt [ ] = {
" x " ,
" y " ,
2018-03-19 23:08:51 +00:00
" f " ,
2014-03-15 16:59:03 +00:00
NULL } ;
enum patch {
patch_valid = 0 ,
patch_width ,
patch_height ,
patch_leftoffset ,
patch_topoffset
} ;
static const char * const patch_opt [ ] = {
" valid " ,
" width " ,
" height " ,
" leftoffset " ,
" topoffset " ,
NULL } ;
2023-06-18 16:05:16 +00:00
static int patch_fields_ref = LUA_NOREF ;
2014-08-04 03:49:33 +00:00
// alignment types for v.drawString
2014-03-15 16:59:03 +00:00
enum align {
align_left = 0 ,
align_center ,
align_right ,
2014-08-04 03:49:33 +00:00
align_fixed ,
2019-08-27 08:36:12 +00:00
align_fixedcenter ,
2019-08-27 08:25:28 +00:00
align_fixedright ,
2014-08-04 03:49:33 +00:00
align_small ,
2019-08-24 16:45:32 +00:00
align_smallfixed ,
2019-09-10 01:41:34 +00:00
align_smallfixedcenter ,
2019-09-10 00:49:04 +00:00
align_smallfixedright ,
2019-08-27 07:57:19 +00:00
align_smallcenter ,
2014-08-04 03:49:33 +00:00
align_smallright ,
2019-08-28 03:44:19 +00:00
align_smallthin ,
2019-10-09 03:16:50 +00:00
align_smallthincenter ,
2019-10-09 03:11:40 +00:00
align_smallthinright ,
2019-09-10 02:25:52 +00:00
align_smallthinfixed ,
2019-10-09 03:03:43 +00:00
align_smallthinfixedcenter ,
2019-10-09 02:54:18 +00:00
align_smallthinfixedright ,
2014-08-04 03:49:33 +00:00
align_thin ,
2019-08-24 14:27:37 +00:00
align_thinfixed ,
2019-09-07 22:55:33 +00:00
align_thinfixedcenter ,
2019-09-07 22:37:21 +00:00
align_thinfixedright ,
2019-08-27 08:05:03 +00:00
align_thincenter ,
2014-08-04 03:49:33 +00:00
align_thinright
2014-03-15 16:59:03 +00:00
} ;
static const char * const align_opt [ ] = {
" left " ,
" center " ,
" right " ,
" fixed " ,
2019-08-27 08:36:12 +00:00
" fixed-center " ,
2019-08-27 08:25:28 +00:00
" fixed-right " ,
2014-08-04 03:49:33 +00:00
" small " ,
2019-08-24 16:45:32 +00:00
" small-fixed " ,
2019-09-10 01:41:34 +00:00
" small-fixed-center " ,
2019-09-10 00:49:04 +00:00
" small-fixed-right " ,
2019-08-27 07:57:19 +00:00
" small-center " ,
2014-08-04 03:49:33 +00:00
" small-right " ,
2019-08-28 03:44:19 +00:00
" small-thin " ,
2019-10-09 03:16:50 +00:00
" small-thin-center " ,
2019-10-09 03:11:40 +00:00
" small-thin-right " ,
2019-09-10 02:25:52 +00:00
" small-thin-fixed " ,
2019-10-09 03:03:43 +00:00
" small-thin-fixed-center " ,
2019-10-09 02:54:18 +00:00
" small-thin-fixed-right " ,
2014-08-04 03:49:33 +00:00
" thin " ,
2019-08-24 14:27:37 +00:00
" thin-fixed " ,
2019-09-07 22:55:33 +00:00
" thin-fixed-center " ,
2019-09-07 22:37:21 +00:00
" thin-fixed-right " ,
2019-08-27 08:05:03 +00:00
" thin-center " ,
2014-08-04 03:49:33 +00:00
" thin-right " ,
NULL } ;
// width types for v.stringWidth
enum widtht {
widtht_normal = 0 ,
widtht_small ,
widtht_thin
} ;
static const char * const widtht_opt [ ] = {
" normal " ,
" small " ,
" thin " ,
NULL } ;
enum cameraf {
camera_chase = 0 ,
camera_aiming ,
camera_x ,
camera_y ,
camera_z ,
camera_angle ,
camera_subsector ,
camera_floorz ,
camera_ceilingz ,
camera_radius ,
camera_height ,
camera_momx ,
camera_momy ,
camera_momz
} ;
static const char * const camera_opt [ ] = {
" chase " ,
" aiming " ,
" x " ,
" y " ,
" z " ,
" angle " ,
" subsector " ,
" floorz " ,
" ceilingz " ,
" radius " ,
" height " ,
" momx " ,
" momy " ,
" momz " ,
2014-03-15 16:59:03 +00:00
NULL } ;
2023-06-18 16:05:16 +00:00
static int camera_fields_ref = LUA_NOREF ;
2014-03-15 16:59:03 +00:00
static int lib_getHudInfo ( lua_State * L )
{
2014-08-27 03:56:30 +00:00
UINT32 i ;
lua_remove ( L , 1 ) ;
i = luaL_checkinteger ( L , 1 ) ;
2016-05-01 21:14:42 +00:00
if ( i > = NUMHUDITEMS )
return luaL_error ( L , " hudinfo[] index %d out of range (0 - %d) " , i, NUMHUDITEMS-1) ;
2014-08-27 03:56:30 +00:00
LUA_PushUserdata ( L , & hudinfo [ i ] , META_HUDINFO ) ;
2014-03-15 16:59:03 +00:00
return 1 ;
}
static int lib_hudinfolen ( lua_State * L )
{
lua_pushinteger ( L , NUMHUDITEMS ) ;
return 1 ;
}
static int hudinfo_get ( lua_State * L )
{
hudinfo_t * info = * ( ( hudinfo_t * * ) luaL_checkudata ( L , 1 , META_HUDINFO ) ) ;
enum hudinfo field = luaL_checkoption ( L , 2 , hudinfo_opt [ 0 ] , hudinfo_opt ) ;
I_Assert ( info ! = NULL ) ; // huditems are always valid
switch ( field )
{
case hudinfo_x :
lua_pushinteger ( L , info - > x ) ;
break ;
case hudinfo_y :
lua_pushinteger ( L , info - > y ) ;
break ;
2018-03-19 23:08:51 +00:00
case hudinfo_f :
lua_pushinteger ( L , info - > f ) ;
break ;
2014-03-15 16:59:03 +00:00
}
return 1 ;
}
static int hudinfo_set ( lua_State * L )
{
hudinfo_t * info = * ( ( hudinfo_t * * ) luaL_checkudata ( L , 1 , META_HUDINFO ) ) ;
enum hudinfo field = luaL_checkoption ( L , 2 , hudinfo_opt [ 0 ] , hudinfo_opt ) ;
I_Assert ( info ! = NULL ) ;
switch ( field )
{
case hudinfo_x :
info - > x = ( INT32 ) luaL_checkinteger ( L , 3 ) ;
break ;
case hudinfo_y :
info - > y = ( INT32 ) luaL_checkinteger ( L , 3 ) ;
break ;
2018-03-19 23:08:51 +00:00
case hudinfo_f :
info - > f = ( INT32 ) luaL_checkinteger ( L , 3 ) ;
break ;
2014-03-15 16:59:03 +00:00
}
return 0 ;
}
static int hudinfo_num ( lua_State * L )
{
hudinfo_t * info = * ( ( hudinfo_t * * ) luaL_checkudata ( L , 1 , META_HUDINFO ) ) ;
lua_pushinteger ( L , info - hudinfo ) ;
return 1 ;
}
2014-11-12 00:55:07 +00:00
static int colormap_get ( lua_State * L )
{
2021-11-08 03:40:53 +00:00
const UINT8 * colormap = * ( ( UINT8 * * ) luaL_checkudata ( L , 1 , META_COLORMAP ) ) ;
2016-06-24 18:17:35 +00:00
UINT32 i = luaL_checkinteger ( L , 2 ) ;
if ( i > = 256 )
return luaL_error ( L , " colormap index %d out of range (0 - %d) " , i, 255) ;
lua_pushinteger ( L , colormap [ i ] ) ;
return 1 ;
2014-11-12 00:55:07 +00:00
}
2014-03-15 16:59:03 +00:00
static int patch_get ( lua_State * L )
{
patch_t * patch = * ( ( patch_t * * ) luaL_checkudata ( L , 1 , META_PATCH ) ) ;
2023-06-18 16:05:16 +00:00
enum patch field = Lua_optoption ( L , 2 , - 1 , patch_fields_ref ) ;
2014-03-15 16:59:03 +00:00
2020-02-12 05:24:43 +00:00
if ( ! patch ) {
if ( field = = patch_valid ) {
lua_pushboolean ( L , 0 ) ;
return 1 ;
}
2019-09-09 20:24:13 +00:00
return LUA_ErrInvalid ( L , " patch_t " ) ;
2020-02-12 05:24:43 +00:00
}
2014-03-15 16:59:03 +00:00
switch ( field )
{
case patch_valid :
lua_pushboolean ( L , patch ! = NULL ) ;
break ;
case patch_width :
2020-11-22 20:22:18 +00:00
lua_pushinteger ( L , patch - > width ) ;
2014-03-15 16:59:03 +00:00
break ;
case patch_height :
2020-11-22 20:22:18 +00:00
lua_pushinteger ( L , patch - > height ) ;
2014-03-15 16:59:03 +00:00
break ;
case patch_leftoffset :
2020-11-22 20:22:18 +00:00
lua_pushinteger ( L , patch - > leftoffset ) ;
2014-03-15 16:59:03 +00:00
break ;
case patch_topoffset :
2020-11-22 20:22:18 +00:00
lua_pushinteger ( L , patch - > topoffset ) ;
2014-03-15 16:59:03 +00:00
break ;
}
return 1 ;
}
static int patch_set ( lua_State * L )
{
return luaL_error ( L , LUA_QL ( " patch_t " ) " struct cannot be edited by Lua. " ) ;
}
2014-08-04 03:49:33 +00:00
static int camera_get ( lua_State * L )
{
camera_t * cam = * ( ( camera_t * * ) luaL_checkudata ( L , 1 , META_CAMERA ) ) ;
2023-06-18 16:05:16 +00:00
enum cameraf field = Lua_optoption ( L , 2 , - 1 , camera_fields_ref ) ;
2014-08-04 03:49:33 +00:00
// cameras should always be valid unless I'm a nutter
I_Assert ( cam ! = NULL ) ;
switch ( field )
{
case camera_chase :
lua_pushboolean ( L , cam - > chase ) ;
break ;
case camera_aiming :
lua_pushinteger ( L , cam - > aiming ) ;
break ;
case camera_x :
lua_pushinteger ( L , cam - > x ) ;
break ;
case camera_y :
lua_pushinteger ( L , cam - > y ) ;
break ;
case camera_z :
lua_pushinteger ( L , cam - > z ) ;
break ;
case camera_angle :
lua_pushinteger ( L , cam - > angle ) ;
break ;
case camera_subsector :
LUA_PushUserdata ( L , cam - > subsector , META_SUBSECTOR ) ;
break ;
case camera_floorz :
lua_pushinteger ( L , cam - > floorz ) ;
break ;
case camera_ceilingz :
lua_pushinteger ( L , cam - > ceilingz ) ;
break ;
case camera_radius :
lua_pushinteger ( L , cam - > radius ) ;
break ;
case camera_height :
lua_pushinteger ( L , cam - > height ) ;
break ;
case camera_momx :
lua_pushinteger ( L , cam - > momx ) ;
break ;
case camera_momy :
lua_pushinteger ( L , cam - > momy ) ;
break ;
case camera_momz :
lua_pushinteger ( L , cam - > momz ) ;
break ;
}
return 1 ;
}
2021-07-10 08:22:07 +00:00
static int camera_set ( lua_State * L )
{
camera_t * cam = * ( ( camera_t * * ) luaL_checkudata ( L , 1 , META_CAMERA ) ) ;
2023-06-18 16:05:16 +00:00
enum cameraf field = Lua_optoption ( L , 2 , - 1 , camera_fields_ref ) ;
2021-07-10 08:22:07 +00:00
I_Assert ( cam ! = NULL ) ;
switch ( field )
{
case camera_subsector :
case camera_floorz :
case camera_ceilingz :
2021-07-11 06:23:50 +00:00
case camera_x :
case camera_y :
return luaL_error ( L , LUA_QL ( " camera_t " ) " field " LUA_QS " should not be set directly. Use " LUA_QL ( " P_TryCameraMove " ) " or " LUA_QL ( " P_TeleportCameraMove " ) " instead. " , camera_opt [ field ] ) ;
2021-09-13 01:53:51 +00:00
case camera_chase : {
INT32 chase = luaL_checkboolean ( L , 3 ) ;
2021-07-10 08:22:07 +00:00
if ( cam = = & camera )
2021-09-13 01:53:51 +00:00
CV_SetValue ( & cv_chasecam , chase ) ;
2021-07-10 08:22:07 +00:00
else if ( cam = = & camera2 )
2021-09-13 01:53:51 +00:00
CV_SetValue ( & cv_chasecam2 , chase ) ;
2021-07-10 08:22:07 +00:00
else // ??? this should never happen, but ok
2021-09-13 01:53:51 +00:00
cam - > chase = chase ;
2021-07-10 08:22:07 +00:00
break ;
2021-09-13 01:53:51 +00:00
}
2021-07-10 08:22:07 +00:00
case camera_aiming :
cam - > aiming = luaL_checkangle ( L , 3 ) ;
break ;
case camera_z :
cam - > z = luaL_checkfixed ( L , 3 ) ;
2021-07-11 06:23:50 +00:00
P_CheckCameraPosition ( cam - > x , cam - > y , cam ) ;
cam - > floorz = tmfloorz ;
cam - > ceilingz = tmceilingz ;
2021-07-10 08:22:07 +00:00
break ;
case camera_angle :
cam - > angle = luaL_checkangle ( L , 3 ) ;
break ;
2021-07-11 06:23:50 +00:00
case camera_radius :
cam - > radius = luaL_checkfixed ( L , 3 ) ;
if ( cam - > radius < 0 )
cam - > radius = 0 ;
P_CheckCameraPosition ( cam - > x , cam - > y , cam ) ;
cam - > floorz = tmfloorz ;
cam - > ceilingz = tmceilingz ;
break ;
case camera_height :
cam - > height = luaL_checkfixed ( L , 3 ) ;
if ( cam - > height < 0 )
cam - > height = 0 ;
P_CheckCameraPosition ( cam - > x , cam - > y , cam ) ;
cam - > floorz = tmfloorz ;
cam - > ceilingz = tmceilingz ;
break ;
2021-07-10 08:22:07 +00:00
case camera_momx :
cam - > momx = luaL_checkfixed ( L , 3 ) ;
break ;
case camera_momy :
cam - > momy = luaL_checkfixed ( L , 3 ) ;
break ;
case camera_momz :
cam - > momz = luaL_checkfixed ( L , 3 ) ;
break ;
default :
2023-08-31 18:02:59 +00:00
return luaL_error ( L , LUA_QL ( " camera_t " ) " has no field named " LUA_QS " . " , lua_tostring ( L , 2 ) ) ;
2021-07-10 08:22:07 +00:00
}
return 0 ;
}
2014-03-15 16:59:03 +00:00
//
// lib_draw
//
2014-03-23 16:00:29 +00:00
static int libd_patchExists ( lua_State * L )
{
2014-08-04 03:49:33 +00:00
HUDONLY
2014-03-25 02:17:59 +00:00
lua_pushboolean ( L , W_LumpExists ( luaL_checkstring ( L , 1 ) ) ) ;
2014-03-23 16:00:29 +00:00
return 1 ;
}
2014-03-15 16:59:03 +00:00
static int libd_cachePatch ( lua_State * L )
{
2014-08-04 03:49:33 +00:00
HUDONLY
2020-04-25 22:39:52 +00:00
LUA_PushUserdata ( L , W_CachePatchLongName ( luaL_checkstring ( L , 1 ) , PU_PATCH ) , META_PATCH ) ;
2014-03-15 16:59:03 +00:00
return 1 ;
}
2020-02-10 07:00:37 +00:00
// v.getSpritePatch(sprite, [frame, [angle, [rollangle]]])
2017-04-30 21:53:05 +00:00
static int libd_getSpritePatch ( lua_State * L )
{
UINT32 i ; // sprite prefix
UINT32 frame = 0 ; // 'A'
UINT8 angle = 0 ;
spritedef_t * sprdef ;
spriteframe_t * sprframe ;
HUDONLY
if ( lua_isnumber ( L , 1 ) ) // sprite number given, e.g. SPR_THOK
{
i = lua_tonumber ( L , 1 ) ;
if ( i > = NUMSPRITES )
return 0 ;
}
else if ( lua_isstring ( L , 1 ) ) // sprite prefix name given, e.g. "THOK"
{
const char * name = lua_tostring ( L , 1 ) ;
for ( i = 0 ; i < NUMSPRITES ; i + + )
if ( fastcmp ( name , sprnames [ i ] ) )
break ;
if ( i > = NUMSPRITES )
return 0 ;
}
else
return 0 ;
if ( i = = SPR_PLAY ) // Use getSprite2Patch instead!
return 0 ;
sprdef = & sprites [ i ] ;
// set frame number
2017-05-13 20:28:44 +00:00
frame = luaL_optinteger ( L , 2 , 0 ) ;
2017-04-30 21:53:05 +00:00
frame & = FF_FRAMEMASK ; // ignore any bits that are not the actual frame, just in case
if ( frame > = sprdef - > numframes )
return 0 ;
// set angle number
2017-05-13 20:28:44 +00:00
sprframe = & sprdef - > spriteframes [ frame ] ;
2017-07-17 20:31:33 +00:00
angle = luaL_optinteger ( L , 3 , 1 ) ;
// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
2020-01-08 20:49:14 +00:00
// in case somebody didn't know that angle 0 really just maps all 8/16 angles to the same patch
2017-07-17 20:31:33 +00:00
if ( angle ! = 0 )
angle - - ;
2020-01-08 20:49:14 +00:00
if ( angle > = ( ( sprframe - > rotate & SRF_3DGE ) ? 16 : 8 ) ) // out of range?
2017-04-30 21:53:05 +00:00
return 0 ;
2020-02-10 07:00:37 +00:00
# ifdef ROTSPRITE
if ( lua_isnumber ( L , 4 ) )
{
// rotsprite?????
angle_t rollangle = luaL_checkangle ( L , 4 ) ;
INT32 rot = R_GetRollAngle ( rollangle ) ;
if ( rot ) {
2020-10-12 03:13:22 +00:00
patch_t * rotsprite = Patch_GetRotatedSprite ( sprframe , frame , angle , sprframe - > flip & ( 1 < < angle ) , true , & spriteinfo [ i ] , rot ) ;
2020-10-10 21:43:26 +00:00
LUA_PushUserdata ( L , rotsprite , META_PATCH ) ;
2020-02-10 07:00:37 +00:00
lua_pushboolean ( L , false ) ;
lua_pushboolean ( L , true ) ;
return 3 ;
}
}
# endif
2017-04-30 21:53:05 +00:00
// push both the patch and it's "flip" value
2020-09-07 05:23:07 +00:00
LUA_PushUserdata ( L , W_CachePatchNum ( sprframe - > lumppat [ angle ] , PU_SPRITE ) , META_PATCH ) ;
2017-04-30 21:53:05 +00:00
lua_pushboolean ( L , ( sprframe - > flip & ( 1 < < angle ) ) ! = 0 ) ;
return 2 ;
}
2020-02-10 07:00:37 +00:00
// v.getSprite2Patch(skin, sprite, [super?,] [frame, [angle, [rollangle]]])
2017-04-30 21:53:05 +00:00
static int libd_getSprite2Patch ( lua_State * L )
{
2017-05-13 20:28:44 +00:00
INT32 i ; // skin number
2018-01-04 19:49:15 +00:00
playersprite_t j ; // sprite2 prefix
2017-04-30 21:53:05 +00:00
UINT32 frame = 0 ; // 'A'
UINT8 angle = 0 ;
spritedef_t * sprdef ;
spriteframe_t * sprframe ;
2017-07-09 15:33:43 +00:00
boolean super = false ; // add FF_SPR2SUPER to sprite2 if true
2017-04-30 21:53:05 +00:00
HUDONLY
// get skin first!
if ( lua_isnumber ( L , 1 ) ) // find skin by number
{
i = lua_tonumber ( L , 1 ) ;
2017-05-13 20:28:44 +00:00
if ( i < 0 | | i > = MAXSKINS )
2017-04-30 21:53:05 +00:00
return luaL_error ( L , " skin number %d out of range (0 - %d) " , i, MAXSKINS-1) ;
if ( i > = numskins )
return 0 ;
}
else // find skin by name
{
const char * name = luaL_checkstring ( L , 1 ) ;
for ( i = 0 ; i < numskins ; i + + )
2017-05-13 20:28:44 +00:00
if ( fastcmp ( skins [ i ] . name , name ) )
2017-04-30 21:53:05 +00:00
break ;
if ( i > = numskins )
return 0 ;
}
lua_remove ( L , 1 ) ; // remove skin now
if ( lua_isnumber ( L , 1 ) ) // sprite number given, e.g. SPR2_STND
{
j = lua_tonumber ( L , 1 ) ;
2017-07-09 15:33:43 +00:00
if ( j & FF_SPR2SUPER ) // e.g. SPR2_STND|FF_SPR2SUPER
{
super = true ;
j & = ~ FF_SPR2SUPER ; // remove flag so the next check doesn't fail
}
2017-04-30 21:53:05 +00:00
if ( j > = free_spr2 )
return 0 ;
}
else if ( lua_isstring ( L , 1 ) ) // sprite prefix name given, e.g. "STND"
{
const char * name = lua_tostring ( L , 1 ) ;
for ( j = 0 ; j < free_spr2 ; j + + )
2017-05-13 20:43:04 +00:00
if ( fastcmp ( name , spr2names [ j ] ) )
2017-04-30 21:53:05 +00:00
break ;
2017-07-09 15:33:43 +00:00
// if you want super flags you'll have to use the optional boolean following this
2017-04-30 21:53:05 +00:00
if ( j > = free_spr2 )
return 0 ;
}
else
return 0 ;
2017-07-09 15:33:43 +00:00
if ( lua_isboolean ( L , 2 ) ) // optional boolean for superness
{
super = lua_toboolean ( L , 2 ) ; // note: this can override FF_SPR2SUPER from sprite number
lua_remove ( L , 2 ) ; // remove
}
// if it's not boolean then just assume it's the frame number
if ( super )
j | = FF_SPR2SUPER ;
2017-08-16 20:00:18 +00:00
j = P_GetSkinSprite2 ( & skins [ i ] , j , NULL ) ; // feed skin and current sprite2 through to change sprite2 used if necessary
2017-04-30 21:53:05 +00:00
sprdef = & skins [ i ] . sprites [ j ] ;
// set frame number
2017-05-13 20:28:44 +00:00
frame = luaL_optinteger ( L , 2 , 0 ) ;
2017-04-30 21:53:05 +00:00
frame & = FF_FRAMEMASK ; // ignore any bits that are not the actual frame, just in case
if ( frame > = sprdef - > numframes )
return 0 ;
// set angle number
2017-05-13 20:28:44 +00:00
sprframe = & sprdef - > spriteframes [ frame ] ;
2017-07-17 20:31:33 +00:00
angle = luaL_optinteger ( L , 3 , 1 ) ;
// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
2020-01-08 20:49:14 +00:00
// in case somebody didn't know that angle 0 really just maps all 8/16 angles to the same patch
2017-07-17 20:31:33 +00:00
if ( angle ! = 0 )
angle - - ;
2020-01-08 20:49:14 +00:00
if ( angle > = ( ( sprframe - > rotate & SRF_3DGE ) ? 16 : 8 ) ) // out of range?
2017-04-30 21:53:05 +00:00
return 0 ;
2020-02-10 07:00:37 +00:00
# ifdef ROTSPRITE
if ( lua_isnumber ( L , 4 ) )
{
// rotsprite?????
angle_t rollangle = luaL_checkangle ( L , 4 ) ;
INT32 rot = R_GetRollAngle ( rollangle ) ;
if ( rot ) {
2020-10-12 03:13:22 +00:00
patch_t * rotsprite = Patch_GetRotatedSprite ( sprframe , frame , angle , sprframe - > flip & ( 1 < < angle ) , true , & skins [ i ] . sprinfo [ j ] , rot ) ;
2020-10-10 21:43:26 +00:00
LUA_PushUserdata ( L , rotsprite , META_PATCH ) ;
2020-02-10 07:00:37 +00:00
lua_pushboolean ( L , false ) ;
lua_pushboolean ( L , true ) ;
return 3 ;
}
}
# endif
2017-04-30 21:53:05 +00:00
// push both the patch and it's "flip" value
2020-09-07 05:23:07 +00:00
LUA_PushUserdata ( L , W_CachePatchNum ( sprframe - > lumppat [ angle ] , PU_SPRITE ) , META_PATCH ) ;
2017-04-30 21:53:05 +00:00
lua_pushboolean ( L , ( sprframe - > flip & ( 1 < < angle ) ) ! = 0 ) ;
return 2 ;
}
2014-03-15 16:59:03 +00:00
static int libd_draw ( lua_State * L )
{
INT32 x , y , flags ;
patch_t * patch ;
2022-04-30 06:50:12 +00:00
UINT8 * colormap = NULL ;
huddrawlist_h list ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
HUDONLY
2014-03-15 16:59:03 +00:00
x = luaL_checkinteger ( L , 1 ) ;
y = luaL_checkinteger ( L , 2 ) ;
patch = * ( ( patch_t * * ) luaL_checkudata ( L , 3 , META_PATCH ) ) ;
2019-09-09 20:24:13 +00:00
if ( ! patch )
return LUA_ErrInvalid ( L , " patch_t " ) ;
2014-03-15 16:59:03 +00:00
flags = luaL_optinteger ( L , 4 , 0 ) ;
if ( ! lua_isnoneornil ( L , 5 ) )
2014-11-12 00:55:07 +00:00
colormap = * ( ( UINT8 * * ) luaL_checkudata ( L , 5 , META_COLORMAP ) ) ;
2014-03-15 16:59:03 +00:00
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDraw ( list , x , y , patch , flags , colormap ) ;
else
V_DrawFixedPatch ( x < < FRACBITS , y < < FRACBITS , FRACUNIT , flags , patch , colormap ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
static int libd_drawScaled ( lua_State * L )
{
fixed_t x , y , scale ;
INT32 flags ;
patch_t * patch ;
2022-04-30 06:50:12 +00:00
UINT8 * colormap = NULL ;
huddrawlist_h list ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
HUDONLY
2014-03-15 16:59:03 +00:00
x = luaL_checkinteger ( L , 1 ) ;
y = luaL_checkinteger ( L , 2 ) ;
2014-03-21 18:42:55 +00:00
scale = luaL_checkinteger ( L , 3 ) ;
2016-10-18 21:07:20 +00:00
if ( scale < 0 )
return luaL_error ( L , " negative scale " ) ;
2014-03-21 18:42:55 +00:00
patch = * ( ( patch_t * * ) luaL_checkudata ( L , 4 , META_PATCH ) ) ;
2019-09-09 20:24:13 +00:00
if ( ! patch )
return LUA_ErrInvalid ( L , " patch_t " ) ;
2014-03-21 18:42:55 +00:00
flags = luaL_optinteger ( L , 5 , 0 ) ;
if ( ! lua_isnoneornil ( L , 6 ) )
2014-11-12 00:55:07 +00:00
colormap = * ( ( UINT8 * * ) luaL_checkudata ( L , 6 , META_COLORMAP ) ) ;
2014-03-21 18:42:55 +00:00
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawScaled ( list , x , y , scale , patch , flags , colormap ) ;
else
V_DrawFixedPatch ( x , y , scale , flags , patch , colormap ) ;
2014-03-21 18:42:55 +00:00
return 0 ;
}
Sound test is cool now!
https://cdn.discordapp.com/attachments/405336003239477249/641295998395613224/srb20042.gif
* Port MUSICDEFs from Kart.
* Safe to modify without modifying game, so we can put it in music.dta eventually.
* "Title", "AltTitle", "Authors" fields are self-evident.
* "Soundtestpage" and "Soundtestcond" are used to determine which sound test unlockable can play them (set with Unlockable's variable, just like Level Select).
* "Stoppingtime" and "BPM" both accept floats, and are used for presentation stuff on the sound test.
* Ironically, we don't share a single field name with them. Such is the case of differing foci, though, and I expect they'll change their implementation to match (since this is necessary for a sound test).
* Change how S_AddSoundFx works to avoid iterating through all of them, and to allow cv_soundtest to only scroll through defined slots (instead of the infinite wall of thok sounds when scrolling to the left).
* Change V_DrawFixedPatch to allow scaling on two seperate axes.
* Now called "V_DrawStretchyFixedPatch".
* "V_DrawFixedPatch" is a macro to V_DrawStretchyFixedPatch now (same scale on both axes).
* Available to Lua under v.drawStretched!
* Even works in GL!
* Bugfix: Add SR_PLAYER to SOC's menutypes_list.
Stay tuned for the merge request, where I put the onus on the Music Team to finish this off...
2019-11-05 16:23:46 +00:00
static int libd_drawStretched ( lua_State * L )
{
fixed_t x , y , hscale , vscale ;
INT32 flags ;
patch_t * patch ;
2022-04-30 06:50:12 +00:00
UINT8 * colormap = NULL ;
huddrawlist_h list ;
Sound test is cool now!
https://cdn.discordapp.com/attachments/405336003239477249/641295998395613224/srb20042.gif
* Port MUSICDEFs from Kart.
* Safe to modify without modifying game, so we can put it in music.dta eventually.
* "Title", "AltTitle", "Authors" fields are self-evident.
* "Soundtestpage" and "Soundtestcond" are used to determine which sound test unlockable can play them (set with Unlockable's variable, just like Level Select).
* "Stoppingtime" and "BPM" both accept floats, and are used for presentation stuff on the sound test.
* Ironically, we don't share a single field name with them. Such is the case of differing foci, though, and I expect they'll change their implementation to match (since this is necessary for a sound test).
* Change how S_AddSoundFx works to avoid iterating through all of them, and to allow cv_soundtest to only scroll through defined slots (instead of the infinite wall of thok sounds when scrolling to the left).
* Change V_DrawFixedPatch to allow scaling on two seperate axes.
* Now called "V_DrawStretchyFixedPatch".
* "V_DrawFixedPatch" is a macro to V_DrawStretchyFixedPatch now (same scale on both axes).
* Available to Lua under v.drawStretched!
* Even works in GL!
* Bugfix: Add SR_PLAYER to SOC's menutypes_list.
Stay tuned for the merge request, where I put the onus on the Music Team to finish this off...
2019-11-05 16:23:46 +00:00
HUDONLY
x = luaL_checkinteger ( L , 1 ) ;
y = luaL_checkinteger ( L , 2 ) ;
hscale = luaL_checkinteger ( L , 3 ) ;
if ( hscale < 0 )
return luaL_error ( L , " negative horizontal scale " ) ;
vscale = luaL_checkinteger ( L , 4 ) ;
if ( vscale < 0 )
return luaL_error ( L , " negative vertical scale " ) ;
patch = * ( ( patch_t * * ) luaL_checkudata ( L , 5 , META_PATCH ) ) ;
flags = luaL_optinteger ( L , 6 , 0 ) ;
if ( ! lua_isnoneornil ( L , 7 ) )
colormap = * ( ( UINT8 * * ) luaL_checkudata ( L , 7 , META_COLORMAP ) ) ;
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawStretched ( list , x , y , hscale , vscale , patch , flags , colormap ) ;
else
V_DrawStretchyFixedPatch ( x , y , hscale , vscale , flags , patch , colormap ) ;
Sound test is cool now!
https://cdn.discordapp.com/attachments/405336003239477249/641295998395613224/srb20042.gif
* Port MUSICDEFs from Kart.
* Safe to modify without modifying game, so we can put it in music.dta eventually.
* "Title", "AltTitle", "Authors" fields are self-evident.
* "Soundtestpage" and "Soundtestcond" are used to determine which sound test unlockable can play them (set with Unlockable's variable, just like Level Select).
* "Stoppingtime" and "BPM" both accept floats, and are used for presentation stuff on the sound test.
* Ironically, we don't share a single field name with them. Such is the case of differing foci, though, and I expect they'll change their implementation to match (since this is necessary for a sound test).
* Change how S_AddSoundFx works to avoid iterating through all of them, and to allow cv_soundtest to only scroll through defined slots (instead of the infinite wall of thok sounds when scrolling to the left).
* Change V_DrawFixedPatch to allow scaling on two seperate axes.
* Now called "V_DrawStretchyFixedPatch".
* "V_DrawFixedPatch" is a macro to V_DrawStretchyFixedPatch now (same scale on both axes).
* Available to Lua under v.drawStretched!
* Even works in GL!
* Bugfix: Add SR_PLAYER to SOC's menutypes_list.
Stay tuned for the merge request, where I put the onus on the Music Team to finish this off...
2019-11-05 16:23:46 +00:00
return 0 ;
}
2020-12-11 22:43:38 +00:00
static int libd_drawCropped ( lua_State * L )
{
fixed_t x , y , hscale , vscale , sx , sy , w , h ;
INT32 flags ;
patch_t * patch ;
2022-04-30 06:50:12 +00:00
UINT8 * colormap = NULL ;
huddrawlist_h list ;
2020-12-11 22:43:38 +00:00
HUDONLY
x = luaL_checkinteger ( L , 1 ) ;
y = luaL_checkinteger ( L , 2 ) ;
hscale = luaL_checkinteger ( L , 3 ) ;
if ( hscale < 0 )
return luaL_error ( L , " negative horizontal scale " ) ;
vscale = luaL_checkinteger ( L , 4 ) ;
if ( vscale < 0 )
return luaL_error ( L , " negative vertical scale " ) ;
patch = * ( ( patch_t * * ) luaL_checkudata ( L , 5 , META_PATCH ) ) ;
flags = luaL_checkinteger ( L , 6 ) ;
if ( ! lua_isnoneornil ( L , 7 ) )
colormap = * ( ( UINT8 * * ) luaL_checkudata ( L , 7 , META_COLORMAP ) ) ;
sx = luaL_checkinteger ( L , 8 ) ;
if ( sx < 0 ) // Don't crash. Now, we could do "x-=sx*FRACUNIT; sx=0;" here...
return luaL_error ( L , " negative crop sx " ) ;
sy = luaL_checkinteger ( L , 9 ) ;
if ( sy < 0 ) // ...but it's more truthful to just deny it, as negative values would crash
return luaL_error ( L , " negative crop sy " ) ;
w = luaL_checkinteger ( L , 10 ) ;
if ( w < 0 ) // Again, don't crash
return luaL_error ( L , " negative crop w " ) ;
h = luaL_checkinteger ( L , 11 ) ;
if ( h < 0 )
return luaL_error ( L , " negative crop h " ) ;
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawCropped ( list , x , y , hscale , vscale , patch , flags , colormap , sx , sy , w , h ) ;
else
V_DrawCroppedPatch ( x , y , hscale , vscale , flags , patch , colormap , sx , sy , w , h ) ;
2020-12-11 22:43:38 +00:00
return 0 ;
}
2014-03-21 18:42:55 +00:00
static int libd_drawNum ( lua_State * L )
{
INT32 x , y , flags , num ;
2022-04-30 06:50:12 +00:00
huddrawlist_h list ;
2014-08-04 03:49:33 +00:00
HUDONLY
2014-03-21 18:42:55 +00:00
x = luaL_checkinteger ( L , 1 ) ;
y = luaL_checkinteger ( L , 2 ) ;
num = luaL_checkinteger ( L , 3 ) ;
flags = luaL_optinteger ( L , 4 , 0 ) ;
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawNum ( list , x , y , num , flags ) ;
else
V_DrawTallNum ( x , y , flags , num ) ;
2014-03-21 18:42:55 +00:00
return 0 ;
}
static int libd_drawPaddedNum ( lua_State * L )
{
INT32 x , y , flags , num , digits ;
2022-04-30 06:50:12 +00:00
huddrawlist_h list ;
2014-08-04 03:49:33 +00:00
HUDONLY
2014-03-21 18:42:55 +00:00
x = luaL_checkinteger ( L , 1 ) ;
y = luaL_checkinteger ( L , 2 ) ;
2016-03-30 04:22:12 +00:00
num = labs ( luaL_checkinteger ( L , 3 ) ) ;
2014-03-21 18:42:55 +00:00
digits = luaL_optinteger ( L , 4 , 2 ) ;
2014-03-15 16:59:03 +00:00
flags = luaL_optinteger ( L , 5 , 0 ) ;
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawPaddedNum ( list , x , y , num , digits , flags ) ;
else
V_DrawPaddedTallNum ( x , y , flags , num , digits ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
static int libd_drawFill ( lua_State * L )
{
2022-04-30 06:50:12 +00:00
huddrawlist_h list ;
2014-03-15 16:59:03 +00:00
INT32 x = luaL_optinteger ( L , 1 , 0 ) ;
INT32 y = luaL_optinteger ( L , 2 , 0 ) ;
INT32 w = luaL_optinteger ( L , 3 , BASEVIDWIDTH ) ;
INT32 h = luaL_optinteger ( L , 4 , BASEVIDHEIGHT ) ;
INT32 c = luaL_optinteger ( L , 5 , 31 ) ;
2014-08-04 03:49:33 +00:00
HUDONLY
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawFill ( list , x , y , w , h , c ) ;
else
V_DrawFill ( x , y , w , h , c ) ;
2014-03-15 16:59:03 +00:00
return 0 ;
}
static int libd_drawString ( lua_State * L )
{
2022-04-30 06:50:12 +00:00
huddrawlist_h list ;
2014-03-15 16:59:03 +00:00
fixed_t x = luaL_checkinteger ( L , 1 ) ;
fixed_t y = luaL_checkinteger ( L , 2 ) ;
const char * str = luaL_checkstring ( L , 3 ) ;
INT32 flags = luaL_optinteger ( L , 4 , V_ALLOWLOWERCASE ) ;
enum align align = luaL_checkoption ( L , 5 , " left " , align_opt ) ;
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2014-08-04 03:49:33 +00:00
HUDONLY
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
// okay, sorry, this is kind of ugly
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawString ( list , x , y , str , flags , align ) ;
else
2014-03-15 16:59:03 +00:00
switch ( align )
{
2014-08-04 03:49:33 +00:00
// hu_font
2014-03-15 16:59:03 +00:00
case align_left :
V_DrawString ( x , y , flags , str ) ;
break ;
case align_center :
V_DrawCenteredString ( x , y , flags , str ) ;
break ;
case align_right :
V_DrawRightAlignedString ( x , y , flags , str ) ;
break ;
case align_fixed :
V_DrawStringAtFixed ( x , y , flags , str ) ;
break ;
2019-08-27 08:36:12 +00:00
case align_fixedcenter :
V_DrawCenteredStringAtFixed ( x , y , flags , str ) ;
break ;
2019-08-27 08:25:28 +00:00
case align_fixedright :
V_DrawRightAlignedStringAtFixed ( x , y , flags , str ) ;
break ;
2014-08-04 03:49:33 +00:00
// hu_font, 0.5x scale
case align_small :
V_DrawSmallString ( x , y , flags , str ) ;
break ;
2019-08-24 16:45:32 +00:00
case align_smallfixed :
V_DrawSmallStringAtFixed ( x , y , flags , str ) ;
break ;
2019-09-10 01:41:34 +00:00
case align_smallfixedcenter :
V_DrawCenteredSmallStringAtFixed ( x , y , flags , str ) ;
break ;
2019-09-10 00:49:04 +00:00
case align_smallfixedright :
V_DrawRightAlignedSmallStringAtFixed ( x , y , flags , str ) ;
break ;
2019-08-27 07:57:19 +00:00
case align_smallcenter :
V_DrawCenteredSmallString ( x , y , flags , str ) ;
break ;
2014-08-04 03:49:33 +00:00
case align_smallright :
V_DrawRightAlignedSmallString ( x , y , flags , str ) ;
break ;
2019-08-28 03:44:19 +00:00
case align_smallthin :
V_DrawSmallThinString ( x , y , flags , str ) ;
break ;
2019-10-09 03:16:50 +00:00
case align_smallthincenter :
V_DrawCenteredSmallThinString ( x , y , flags , str ) ;
break ;
2019-10-09 03:11:40 +00:00
case align_smallthinright :
V_DrawRightAlignedSmallThinString ( x , y , flags , str ) ;
break ;
2019-09-10 02:25:52 +00:00
case align_smallthinfixed :
V_DrawSmallThinStringAtFixed ( x , y , flags , str ) ;
break ;
2019-10-09 03:03:43 +00:00
case align_smallthinfixedcenter :
V_DrawCenteredSmallThinStringAtFixed ( x , y , flags , str ) ;
break ;
2019-10-09 02:54:18 +00:00
case align_smallthinfixedright :
V_DrawRightAlignedSmallThinStringAtFixed ( x , y , flags , str ) ;
break ;
2014-08-04 03:49:33 +00:00
// tny_font
case align_thin :
V_DrawThinString ( x , y , flags , str ) ;
break ;
2019-08-27 08:05:03 +00:00
case align_thincenter :
V_DrawCenteredThinString ( x , y , flags , str ) ;
break ;
2014-08-04 03:49:33 +00:00
case align_thinright :
V_DrawRightAlignedThinString ( x , y , flags , str ) ;
break ;
2019-08-24 14:27:37 +00:00
case align_thinfixed :
V_DrawThinStringAtFixed ( x , y , flags , str ) ;
break ;
2019-09-07 22:55:33 +00:00
case align_thinfixedcenter :
V_DrawCenteredThinStringAtFixed ( x , y , flags , str ) ;
break ;
2019-09-07 22:37:21 +00:00
case align_thinfixedright :
V_DrawRightAlignedThinStringAtFixed ( x , y , flags , str ) ;
break ;
2014-03-15 16:59:03 +00:00
}
return 0 ;
}
2019-10-14 05:24:44 +00:00
static int libd_drawNameTag ( lua_State * L )
{
INT32 x ;
INT32 y ;
const char * str ;
INT32 flags ;
2020-05-24 00:29:07 +00:00
UINT16 basecolor ;
UINT16 outlinecolor ;
2019-10-14 05:24:44 +00:00
UINT8 * basecolormap = NULL ;
UINT8 * outlinecolormap = NULL ;
2022-04-30 06:50:12 +00:00
huddrawlist_h list ;
2019-10-14 05:24:44 +00:00
HUDONLY
x = luaL_checkinteger ( L , 1 ) ;
y = luaL_checkinteger ( L , 2 ) ;
str = luaL_checkstring ( L , 3 ) ;
flags = luaL_optinteger ( L , 4 , 0 ) ;
basecolor = luaL_optinteger ( L , 5 , SKINCOLOR_BLUE ) ;
outlinecolor = luaL_optinteger ( L , 6 , SKINCOLOR_ORANGE ) ;
if ( basecolor ! = SKINCOLOR_NONE )
basecolormap = R_GetTranslationColormap ( TC_DEFAULT , basecolor , GTC_CACHE ) ;
if ( outlinecolor ! = SKINCOLOR_NONE )
outlinecolormap = R_GetTranslationColormap ( TC_DEFAULT , outlinecolor , GTC_CACHE ) ;
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawNameTag ( list , x , y , str , flags , basecolor , outlinecolor , basecolormap , outlinecolormap ) ;
else
V_DrawNameTag ( x , y , flags , FRACUNIT , basecolormap , outlinecolormap , str ) ;
2019-10-14 05:24:44 +00:00
return 0 ;
}
static int libd_drawScaledNameTag ( lua_State * L )
{
fixed_t x ;
fixed_t y ;
const char * str ;
INT32 flags ;
fixed_t scale ;
2020-05-24 00:29:07 +00:00
UINT16 basecolor ;
UINT16 outlinecolor ;
2019-10-14 05:24:44 +00:00
UINT8 * basecolormap = NULL ;
UINT8 * outlinecolormap = NULL ;
2022-04-30 06:50:12 +00:00
huddrawlist_h list ;
2019-10-14 05:24:44 +00:00
HUDONLY
x = luaL_checkfixed ( L , 1 ) ;
y = luaL_checkfixed ( L , 2 ) ;
str = luaL_checkstring ( L , 3 ) ;
flags = luaL_optinteger ( L , 4 , 0 ) ;
scale = luaL_optinteger ( L , 5 , FRACUNIT ) ;
if ( scale < 0 )
return luaL_error ( L , " negative scale " ) ;
basecolor = luaL_optinteger ( L , 6 , SKINCOLOR_BLUE ) ;
outlinecolor = luaL_optinteger ( L , 7 , SKINCOLOR_ORANGE ) ;
if ( basecolor ! = SKINCOLOR_NONE )
basecolormap = R_GetTranslationColormap ( TC_DEFAULT , basecolor , GTC_CACHE ) ;
if ( outlinecolor ! = SKINCOLOR_NONE )
outlinecolormap = R_GetTranslationColormap ( TC_DEFAULT , outlinecolor , GTC_CACHE ) ;
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawScaledNameTag ( list , x , y , str , flags , scale , basecolor , outlinecolor , basecolormap , outlinecolormap ) ;
else
V_DrawNameTag ( FixedInt ( x ) , FixedInt ( y ) , flags , scale , basecolormap , outlinecolormap , str ) ;
2019-10-14 05:24:44 +00:00
return 0 ;
}
2020-12-17 18:26:27 +00:00
static int libd_drawLevelTitle ( lua_State * L )
{
INT32 x ;
INT32 y ;
const char * str ;
INT32 flags ;
2022-04-30 06:50:12 +00:00
huddrawlist_h list ;
2020-12-17 18:26:27 +00:00
HUDONLY
x = luaL_checkinteger ( L , 1 ) ;
y = luaL_checkinteger ( L , 2 ) ;
str = luaL_checkstring ( L , 3 ) ;
flags = luaL_optinteger ( L , 4 , 0 ) ;
flags & = ~ V_PARAMMASK ; // Don't let crashes happen.
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawLevelTitle ( list , x , y , str , flags ) ;
else
V_DrawLevelTitle ( x , y , flags , str ) ;
2020-12-17 18:26:27 +00:00
return 0 ;
}
2014-03-15 16:59:03 +00:00
static int libd_stringWidth ( lua_State * L )
{
const char * str = luaL_checkstring ( L , 1 ) ;
INT32 flags = luaL_optinteger ( L , 2 , V_ALLOWLOWERCASE ) ;
2014-08-04 03:49:33 +00:00
enum widtht widtht = luaL_checkoption ( L , 3 , " normal " , widtht_opt ) ;
2014-03-15 16:59:03 +00:00
2014-08-04 03:49:33 +00:00
HUDONLY
switch ( widtht )
{
case widtht_normal : // hu_font
lua_pushinteger ( L , V_StringWidth ( str , flags ) ) ;
break ;
case widtht_small : // hu_font, 0.5x scale
lua_pushinteger ( L , V_SmallStringWidth ( str , flags ) ) ;
break ;
case widtht_thin : // tny_font
lua_pushinteger ( L , V_ThinStringWidth ( str , flags ) ) ;
break ;
}
2014-03-15 16:59:03 +00:00
return 1 ;
}
2019-10-14 05:24:44 +00:00
static int libd_nameTagWidth ( lua_State * L )
{
HUDONLY
lua_pushinteger ( L , V_NameTagWidth ( luaL_checkstring ( L , 1 ) ) ) ;
return 1 ;
}
2020-12-17 18:26:27 +00:00
static int libd_levelTitleWidth ( lua_State * L )
{
HUDONLY
lua_pushinteger ( L , V_LevelNameWidth ( luaL_checkstring ( L , 1 ) ) ) ;
return 1 ;
}
static int libd_levelTitleHeight ( lua_State * L )
{
HUDONLY
lua_pushinteger ( L , V_LevelNameHeight ( luaL_checkstring ( L , 1 ) ) ) ;
return 1 ;
}
2014-11-12 00:55:07 +00:00
static int libd_getColormap ( lua_State * L )
{
INT32 skinnum = TC_DEFAULT ;
2020-02-15 08:18:41 +00:00
skincolornum_t color = luaL_optinteger ( L , 2 , 0 ) ;
2014-11-12 00:55:07 +00:00
UINT8 * colormap = NULL ;
2016-01-31 22:52:02 +00:00
HUDONLY
2014-11-12 00:55:07 +00:00
if ( lua_isnoneornil ( L , 1 ) )
; // defaults to TC_DEFAULT
else if ( lua_type ( L , 1 ) = = LUA_TNUMBER ) // skin number
{
skinnum = ( INT32 ) luaL_checkinteger ( L , 1 ) ;
2020-11-28 10:19:52 +00:00
if ( skinnum > = MAXSKINS )
return luaL_error ( L , " skin number %d is out of range (>%d) " , skinnum, MAXSKINS-1) ;
else if ( skinnum < 0 & & skinnum > TC_DEFAULT )
return luaL_error ( L , " translation colormap index is out of range " ) ;
2014-11-12 00:55:07 +00:00
}
else // skin name
{
const char * skinname = luaL_checkstring ( L , 1 ) ;
INT32 i = R_SkinAvailable ( skinname ) ;
if ( i ! = - 1 ) // if -1, just default to TC_DEFAULT as above
skinnum = i ;
}
// all was successful above, now we generate the colormap at last!
2021-11-08 03:40:53 +00:00
colormap = R_GetTranslationColormap ( skinnum , color , GTC_CACHE ) ;
2014-11-12 00:55:07 +00:00
LUA_PushUserdata ( L , colormap , META_COLORMAP ) ; // push as META_COLORMAP userdata, specifically for patches to use!
return 1 ;
}
2020-08-14 04:33:47 +00:00
static int libd_getStringColormap ( lua_State * L )
{
INT32 flags = luaL_checkinteger ( L , 1 ) ;
UINT8 * colormap = NULL ;
HUDONLY
colormap = V_GetStringColormap ( flags & V_CHARCOLORMASK ) ;
if ( colormap ) {
2021-11-08 03:40:53 +00:00
LUA_PushUserdata ( L , colormap , META_COLORMAP ) ; // push as META_COLORMAP userdata, specifically for patches to use!
2020-08-14 04:33:47 +00:00
return 1 ;
}
return 0 ;
}
2018-02-12 17:47:31 +00:00
static int libd_fadeScreen ( lua_State * L )
{
2022-04-30 06:50:12 +00:00
huddrawlist_h list ;
2018-02-12 17:47:31 +00:00
UINT16 color = luaL_checkinteger ( L , 1 ) ;
UINT8 strength = luaL_checkinteger ( L , 2 ) ;
2018-02-12 18:23:57 +00:00
const UINT8 maxstrength = ( ( color & 0xFF00 ) ? 32 : 10 ) ;
2018-02-12 17:47:31 +00:00
HUDONLY
2018-02-12 18:23:57 +00:00
2018-02-12 17:47:31 +00:00
if ( ! strength )
return 0 ;
if ( strength > maxstrength )
return luaL_error ( L , " %s fade strength %d out of range (0 - %d) " , ((color & 0xFF00) ? " COLORMAP " : " TRANSMAP " ), strength, maxstrength) ;
2022-04-30 06:50:12 +00:00
lua_getfield ( L , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
list = ( huddrawlist_h ) lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
2018-02-12 18:23:57 +00:00
if ( strength = = maxstrength ) // Allow as a shortcut for drawfill...
{
2022-04-30 06:50:12 +00:00
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddDrawFill ( list , 0 , 0 , BASEVIDWIDTH , BASEVIDHEIGHT , ( ( color & 0xFF00 ) ? 31 : color ) ) ;
else
V_DrawFill ( 0 , 0 , BASEVIDWIDTH , BASEVIDHEIGHT , ( ( color & 0xFF00 ) ? 31 : color ) ) ;
2018-02-12 18:23:57 +00:00
return 0 ;
}
2022-04-30 06:50:12 +00:00
if ( LUA_HUD_IsDrawListValid ( list ) )
LUA_HUD_AddFadeScreen ( list , color , strength ) ;
else
V_DrawFadeScreen ( color , strength ) ;
2022-11-12 01:31:04 +00:00
2018-02-12 17:47:31 +00:00
return 0 ;
}
2016-01-31 21:53:14 +00:00
static int libd_width ( lua_State * L )
{
HUDONLY
lua_pushinteger ( L , vid . width ) ; // push screen width
return 1 ;
}
static int libd_height ( lua_State * L )
{
HUDONLY
lua_pushinteger ( L , vid . height ) ; // push screen height
return 1 ;
}
2023-10-30 04:38:51 +00:00
static int libd_dup ( lua_State * L )
2016-05-03 05:25:00 +00:00
{
HUDONLY
2023-10-30 04:38:51 +00:00
lua_pushinteger ( L , vid . dup ) ; // push integral scale (patch scale)
lua_pushfixed ( L , vid . fdup ) ; // push fixed point scale (position scale)
2016-05-03 05:25:00 +00:00
return 2 ;
}
2016-01-31 21:53:14 +00:00
static int libd_renderer ( lua_State * L )
{
HUDONLY
2016-01-31 22:15:17 +00:00
switch ( rendermode ) {
case render_opengl : lua_pushliteral ( L , " opengl " ) ; break ; // OpenGL renderer
case render_soft : lua_pushliteral ( L , " software " ) ; break ; // Software renderer
default : lua_pushliteral ( L , " none " ) ; break ; // render_none (for dedicated), in case there's any reason this should be run
}
2016-01-31 21:53:14 +00:00
return 1 ;
}
2018-03-20 15:00:27 +00:00
// M_RANDOM
//////////////
static int libd_RandomFixed ( lua_State * L )
{
HUDONLY
lua_pushfixed ( L , M_RandomFixed ( ) ) ;
return 1 ;
}
static int libd_RandomByte ( lua_State * L )
{
HUDONLY
lua_pushinteger ( L , M_RandomByte ( ) ) ;
return 1 ;
}
static int libd_RandomKey ( lua_State * L )
{
INT32 a = ( INT32 ) luaL_checkinteger ( L , 1 ) ;
HUDONLY
lua_pushinteger ( L , M_RandomKey ( a ) ) ;
return 1 ;
}
static int libd_RandomRange ( lua_State * L )
{
INT32 a = ( INT32 ) luaL_checkinteger ( L , 1 ) ;
INT32 b = ( INT32 ) luaL_checkinteger ( L , 2 ) ;
HUDONLY
lua_pushinteger ( L , M_RandomRange ( a , b ) ) ;
return 1 ;
}
// Macros.
static int libd_SignedRandom ( lua_State * L )
{
HUDONLY
lua_pushinteger ( L , M_SignedRandom ( ) ) ;
return 1 ;
}
static int libd_RandomChance ( lua_State * L )
{
fixed_t p = luaL_checkfixed ( L , 1 ) ;
HUDONLY
lua_pushboolean ( L , M_RandomChance ( p ) ) ;
return 1 ;
}
2019-11-18 14:39:54 +00:00
// 30/10/18 Lat': Get st_translucency's value for HUD rendering as a normal V_xxTRANS int
2018-10-30 18:40:59 +00:00
// Could as well be thrown in global vars for ease of access but I guess it makes sense for it to be a HUD fn
static int libd_getlocaltransflag ( lua_State * L )
2019-11-18 14:39:54 +00:00
{
HUDONLY
lua_pushinteger ( L , ( 10 - st_translucency ) * V_10TRANS ) ;
return 1 ;
}
// Get cv_translucenthud's value for HUD rendering as a normal V_xxTRANS int
static int libd_getusertransflag ( lua_State * L )
2018-10-30 18:40:59 +00:00
{
HUDONLY
lua_pushinteger ( L , ( 10 - cv_translucenthud . value ) * V_10TRANS ) ; // A bit weird that it's called "translucenthud" yet 10 is fully opaque :V
return 1 ;
}
2014-03-15 16:59:03 +00:00
static luaL_Reg lib_draw [ ] = {
2018-03-20 15:00:27 +00:00
// cache
2014-03-23 16:00:29 +00:00
{ " patchExists " , libd_patchExists } ,
2014-03-15 16:59:03 +00:00
{ " cachePatch " , libd_cachePatch } ,
2017-04-30 21:53:05 +00:00
{ " getSpritePatch " , libd_getSpritePatch } ,
{ " getSprite2Patch " , libd_getSprite2Patch } ,
2018-03-20 15:00:27 +00:00
{ " getColormap " , libd_getColormap } ,
2020-08-14 04:33:47 +00:00
{ " getStringColormap " , libd_getStringColormap } ,
2018-03-20 15:00:27 +00:00
// drawing
2014-03-15 16:59:03 +00:00
{ " draw " , libd_draw } ,
{ " drawScaled " , libd_drawScaled } ,
Sound test is cool now!
https://cdn.discordapp.com/attachments/405336003239477249/641295998395613224/srb20042.gif
* Port MUSICDEFs from Kart.
* Safe to modify without modifying game, so we can put it in music.dta eventually.
* "Title", "AltTitle", "Authors" fields are self-evident.
* "Soundtestpage" and "Soundtestcond" are used to determine which sound test unlockable can play them (set with Unlockable's variable, just like Level Select).
* "Stoppingtime" and "BPM" both accept floats, and are used for presentation stuff on the sound test.
* Ironically, we don't share a single field name with them. Such is the case of differing foci, though, and I expect they'll change their implementation to match (since this is necessary for a sound test).
* Change how S_AddSoundFx works to avoid iterating through all of them, and to allow cv_soundtest to only scroll through defined slots (instead of the infinite wall of thok sounds when scrolling to the left).
* Change V_DrawFixedPatch to allow scaling on two seperate axes.
* Now called "V_DrawStretchyFixedPatch".
* "V_DrawFixedPatch" is a macro to V_DrawStretchyFixedPatch now (same scale on both axes).
* Available to Lua under v.drawStretched!
* Even works in GL!
* Bugfix: Add SR_PLAYER to SOC's menutypes_list.
Stay tuned for the merge request, where I put the onus on the Music Team to finish this off...
2019-11-05 16:23:46 +00:00
{ " drawStretched " , libd_drawStretched } ,
2020-12-11 22:43:38 +00:00
{ " drawCropped " , libd_drawCropped } ,
2014-03-21 18:42:55 +00:00
{ " drawNum " , libd_drawNum } ,
{ " drawPaddedNum " , libd_drawPaddedNum } ,
2014-03-15 16:59:03 +00:00
{ " drawFill " , libd_drawFill } ,
{ " drawString " , libd_drawString } ,
2019-10-14 05:24:44 +00:00
{ " drawNameTag " , libd_drawNameTag } ,
{ " drawScaledNameTag " , libd_drawScaledNameTag } ,
2020-12-17 18:26:27 +00:00
{ " drawLevelTitle " , libd_drawLevelTitle } ,
2018-02-12 17:47:31 +00:00
{ " fadeScreen " , libd_fadeScreen } ,
2018-03-20 15:00:27 +00:00
// misc
{ " stringWidth " , libd_stringWidth } ,
2019-10-14 05:24:44 +00:00
{ " nameTagWidth " , libd_nameTagWidth } ,
2020-12-17 18:26:27 +00:00
{ " levelTitleWidth " , libd_levelTitleWidth } ,
{ " levelTitleHeight " , libd_levelTitleHeight } ,
2018-03-20 15:00:27 +00:00
// m_random
{ " RandomFixed " , libd_RandomFixed } ,
{ " RandomByte " , libd_RandomByte } ,
{ " RandomKey " , libd_RandomKey } ,
{ " RandomRange " , libd_RandomRange } ,
{ " SignedRandom " , libd_SignedRandom } , // MACRO
{ " RandomChance " , libd_RandomChance } , // MACRO
// properties
2016-01-31 21:53:14 +00:00
{ " width " , libd_width } ,
{ " height " , libd_height } ,
2023-10-30 04:38:51 +00:00
{ " dupx " , libd_dup } ,
{ " dupy " , libd_dup } ,
2016-01-31 21:53:14 +00:00
{ " renderer " , libd_renderer } ,
2018-10-30 18:40:59 +00:00
{ " localTransFlag " , libd_getlocaltransflag } ,
2019-11-18 14:39:54 +00:00
{ " userTransFlag " , libd_getusertransflag } ,
2014-03-15 16:59:03 +00:00
{ NULL , NULL }
} ;
2021-07-07 07:23:51 +00:00
static int lib_draw_ref ;
2014-03-15 16:59:03 +00:00
//
// lib_hud
//
// enable vanilla HUD element
static int lib_hudenable ( lua_State * L )
{
enum hud option = luaL_checkoption ( L , 1 , NULL , hud_disable_options ) ;
hud_enabled [ option / 8 ] | = 1 < < ( option % 8 ) ;
return 0 ;
}
// disable vanilla HUD element
static int lib_huddisable ( lua_State * L )
{
enum hud option = luaL_checkoption ( L , 1 , NULL , hud_disable_options ) ;
hud_enabled [ option / 8 ] & = ~ ( 1 < < ( option % 8 ) ) ;
return 0 ;
}
2018-10-30 18:40:59 +00:00
// 30/10/18: Lat': How come this wasn't here before?
static int lib_hudenabled ( lua_State * L )
{
enum hud option = luaL_checkoption ( L , 1 , NULL , hud_disable_options ) ;
2018-10-30 21:29:28 +00:00
if ( hud_enabled [ option / 8 ] & ( 1 < < ( option % 8 ) ) )
2018-10-30 18:40:59 +00:00
lua_pushboolean ( L , true ) ;
else
lua_pushboolean ( L , false ) ;
return 1 ;
}
2014-03-15 16:59:03 +00:00
// add a HUD element for rendering
2021-07-07 07:23:51 +00:00
extern int lib_hudadd ( lua_State * L ) ;
2014-03-15 16:59:03 +00:00
static luaL_Reg lib_hud [ ] = {
{ " enable " , lib_hudenable } ,
{ " disable " , lib_huddisable } ,
2018-10-30 18:40:59 +00:00
{ " enabled " , lib_hudenabled } ,
2014-03-15 16:59:03 +00:00
{ " add " , lib_hudadd } ,
{ NULL , NULL }
} ;
//
//
//
int LUA_HudLib ( lua_State * L )
{
memset ( hud_enabled , 0xff , ( hud_MAX / 8 ) + 1 ) ;
2021-07-07 07:23:51 +00:00
lua_newtable ( L ) ;
luaL_register ( L , NULL , lib_draw ) ;
lib_draw_ref = luaL_ref ( L , LUA_REGISTRYINDEX ) ;
2014-03-15 16:59:03 +00:00
2023-10-27 18:17:27 +00:00
LUA_RegisterUserdataMetatable ( L , META_HUDINFO , hudinfo_get , hudinfo_set , hudinfo_num ) ;
LUA_RegisterUserdataMetatable ( L , META_COLORMAP , colormap_get , NULL , NULL ) ;
LUA_RegisterUserdataMetatable ( L , META_PATCH , patch_get , patch_set , NULL ) ;
LUA_RegisterUserdataMetatable ( L , META_CAMERA , camera_get , camera_set , NULL ) ;
2014-03-15 16:59:03 +00:00
2023-06-18 16:05:16 +00:00
patch_fields_ref = Lua_CreateFieldTable ( L , patch_opt ) ;
camera_fields_ref = Lua_CreateFieldTable ( L , camera_opt ) ;
2023-10-27 22:24:04 +00:00
LUA_RegisterGlobalUserdata ( L , " hudinfo " , lib_getHudInfo , NULL , lib_hudinfolen ) ;
2014-03-15 16:59:03 +00:00
luaL_register ( L , " hud " , lib_hud ) ;
return 0 ;
}
boolean LUA_HudEnabled ( enum hud option )
{
if ( ! gL | | hud_enabled [ option / 8 ] & ( 1 < < ( option % 8 ) ) )
return true ;
return false ;
}
2022-04-30 06:50:12 +00:00
void LUA_SetHudHook ( int hook , huddrawlist_h list )
2014-03-15 16:59:03 +00:00
{
2021-07-07 07:23:51 +00:00
lua_getref ( gL , lib_draw_ref ) ;
2014-03-15 16:59:03 +00:00
2022-04-30 06:50:12 +00:00
lua_pushlightuserdata ( gL , list ) ;
lua_setfield ( gL , LUA_REGISTRYINDEX , " HUD_DRAW_LIST " ) ;
2021-07-07 07:23:51 +00:00
switch ( hook )
{
case HUD_HOOK ( game ) : {
camera_t * cam = ( splitscreen & & stplyr = =
& players [ secondarydisplayplayer ] )
? & camera2 : & camera ;
LUA_PushUserdata ( gL , stplyr , META_PLAYER ) ;
LUA_PushUserdata ( gL , cam , META_CAMERA ) ;
} break ;
case HUD_HOOK ( titlecard ) :
LUA_PushUserdata ( gL , stplyr , META_PLAYER ) ;
lua_pushinteger ( gL , lt_ticker ) ;
lua_pushinteger ( gL , ( lt_endtime + TICRATE ) ) ;
break ;
case HUD_HOOK ( intermission ) :
2023-08-07 18:35:20 +00:00
lua_pushboolean ( gL , stagefailed ) ;
2019-12-18 21:09:56 +00:00
}
}