Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2214-pre4
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • acs
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • better-distance-math
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • classic-netcode-fixes
  • cleanup-opengl
  • cleanupmusic
  • clipmidtex
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • extra-textures
  • few-kart-lua-changes
  • ffloorclip
  • fix-167
  • fix-cvar-conflicts
  • fix-dedi-pthread
  • fix-enemy-target
  • fix-opengl-parameter-crash
  • fix-opengl-shear-roll
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • frictionrefactor
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-maxconditionsets
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • just-in-case
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.15
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
142 results

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
  • voltybystorm/SRB2
  • ZenithNeko/srb-2-xp
  • Nep2Disk/SRB2
  • Cloudeon/SRB2
  • mushe/srb-2-ps-b
122 results
Select Git revision
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • better-player-states
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • few-kart-lua-changes
  • ffloorclip
  • fix-1215
  • fix-167
  • fix-cvar-conflicts
  • fix-equation-slopes-near-edges
  • fix-opengl-shear-roll
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • frictionrefactor
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • gitlab-ci
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-debug-library
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • map-components-signedness-fixes
  • master
  • menu-edits
  • mobj-dispoffset
  • more-cleanup
  • movie
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
141 results
Show changes
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2024-2024 by Sonic Team Junior.
//
// 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_interceptlib.c
/// \brief intercept library for Lua scripting
#include "doomdef.h"
#include "fastcmp.h"
#include "p_local.h"
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#define NOHUD if (hud_running)\
return luaL_error(L, "HUD rendering code should not call this function!");
enum intercept_e {
intercept_valid = 0,
intercept_frac,
intercept_thing,
intercept_line
};
static const char *const intercept_opt[] = {
"valid",
"frac",
"thing",
"line",
NULL};
static int intercept_fields_ref = LUA_NOREF;
static boolean Lua_PathTraverser(intercept_t *in)
{
boolean traverse = false;
I_Assert(in != NULL);
lua_settop(gL, 6);
lua_pushcfunction(gL, LUA_GetErrorMessage);
I_Assert(lua_isfunction(gL, -2));
lua_pushvalue(gL, -2);
LUA_PushUserdata(gL, in, META_INTERCEPT);
LUA_Call(gL, 1, 1, -3);
traverse = lua_toboolean(gL, -1);
lua_pop(gL, 1);
return !traverse; // Stay consistent with the MobjMoveCollide hook
}
static int intercept_get(lua_State *L)
{
intercept_t *in = *((intercept_t **)luaL_checkudata(L, 1, META_INTERCEPT));
enum intercept_e field = Lua_optoption(L, 2, intercept_valid, intercept_fields_ref);
if (!in)
{
if (field == intercept_valid) {
lua_pushboolean(L, 0);
return 1;
}
return luaL_error(L, "accessed intercept_t doesn't exist anymore.");
}
switch(field)
{
case intercept_valid: // valid
lua_pushboolean(L, 1);
return 1;
case intercept_frac:
lua_pushfixed(L, in->frac);
return 1;
case intercept_thing:
if (in->isaline)
return 0;
LUA_PushUserdata(L, in->d.thing, META_MOBJ);
return 1;
case intercept_line:
if (!in->isaline)
return 0;
LUA_PushUserdata(L, in->d.line, META_LINE);
return 1;
}
return 0;
}
static int lib_pPathTraverse(lua_State *L)
{
fixed_t px1 = luaL_checkfixed(L, 1);
fixed_t py1 = luaL_checkfixed(L, 2);
fixed_t px2 = luaL_checkfixed(L, 3);
fixed_t py2 = luaL_checkfixed(L, 4);
INT32 flags = (INT32)luaL_checkinteger(L, 5);
luaL_checktype(L, 6, LUA_TFUNCTION);
NOHUD
INLEVEL
lua_pushboolean(L, P_PathTraverse(px1, py1, px2, py2, flags, Lua_PathTraverser));
return 1;
}
int LUA_InterceptLib(lua_State *L)
{
LUA_RegisterUserdataMetatable(L, META_INTERCEPT, intercept_get, NULL, NULL);
intercept_fields_ref = Lua_CreateFieldTable(L, intercept_opt);
lua_register(L, "P_PathTraverse", lib_pPathTraverse);
return 0;
}
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -13,6 +13,7 @@
extern lua_State *gL;
extern boolean mousegrabbedbylua;
extern boolean textinputmodeenabledbylua;
extern boolean ignoregameinputs;
#define MUTABLE_TAGS
......@@ -29,6 +30,8 @@ extern boolean ignoregameinputs;
#define META_SKINCOLOR "SKINCOLOR_T*"
#define META_COLORRAMP "SKINCOLOR_T*RAMP"
#define META_SPRITEINFO "SPRITEINFO_T*"
#define META_SPRITEINFOFRAMELIST "SPRITEINFOFRAME_T[]"
#define META_SPRITEINFOFRAME "SPRITEINFOFRAME_T*"
#define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
#define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"
......@@ -42,8 +45,11 @@ extern boolean ignoregameinputs;
#define META_SKIN "SKIN_T*"
#define META_POWERS "PLAYER_T*POWERS"
#define META_SOUNDSID "SKIN_T*SOUNDSID"
#define META_SKINSPRITES "SKIN_T*SPRITES"
#define META_SKINSPRITESLIST "SKIN_T*SPRITES[]"
#define META_SKINSPRITES "SKIN_T*SKINSPRITES"
#define META_SKINSPRITESLIST "SKIN_T*SKINSPRITES[]"
#define META_SKINSPRITESCOMPAT "SKIN_T*SPRITES" // TODO: 2.3: Delete
#define META_MUSICDEF "MUSICDEF_T*"
#define META_VERTEX "VERTEX_T*"
#define META_LINE "LINE_T*"
......@@ -51,13 +57,7 @@ extern boolean ignoregameinputs;
#define META_SUBSECTOR "SUBSECTOR_T*"
#define META_SECTOR "SECTOR_T*"
#define META_FFLOOR "FFLOOR_T*"
#ifdef HAVE_LUA_SEGS
#define META_SEG "SEG_T*"
#define META_NODE "NODE_T*"
#endif
#define META_SLOPE "PSLOPE_T*"
#define META_VECTOR2 "VECTOR2_T"
#define META_VECTOR3 "VECTOR3_T"
#define META_MAPHEADER "MAPHEADER_T*"
#define META_POLYOBJ "POLYOBJ_T*"
......@@ -68,17 +68,17 @@ extern boolean ignoregameinputs;
#ifdef MUTABLE_TAGS
#define META_SECTORTAGLIST "sector_t.taglist"
#endif
#define META_SECTORCUSTOMARGS "SECTOR_T*CUSTOMARGS"
#define META_SIDENUM "LINE_T*SIDENUM"
#define META_LINEARGS "LINE_T*ARGS"
#define META_LINESTRINGARGS "LINE_T*STRINGARGS"
#define META_LINECUSTOMARGS "LINE_T*CUSTOMARGS"
#define META_SIDECUSTOMARGS "SIDE_T*CUSTOMARGS"
#define META_THINGARGS "MAPTHING_T*ARGS"
#define META_THINGSTRINGARGS "MAPTHING_T*STRINGARGS"
#define META_THINGCUSTOMARGS "MAPTHING_T*CUSTOMARGS"
#define META_POLYOBJVERTICES "POLYOBJ_T*VERTICES"
#define META_POLYOBJLINES "POLYOBJ_T*LINES"
#ifdef HAVE_LUA_SEGS
#define META_NODEBBOX "NODE_T*BBOX"
#define META_NODECHILDREN "NODE_T*CHILDREN"
#endif
#define META_BBOX "BOUNDING_BOX"
......@@ -92,9 +92,17 @@ extern boolean ignoregameinputs;
#define META_LUABANKS "LUABANKS[]*"
#define META_TEXTEVENT "TEXTEVENT_T*"
#define META_KEYEVENT "KEYEVENT_T*"
#define META_MOUSE "MOUSE_T*"
#define META_INTERCEPT "INTERCEPT_T*"
#define META_VECTOR2 "VECTOR2_T"
#define META_VECTOR3 "VECTOR3_T"
#define META_MATRIX "MATRIX_T"
#define META_QUATERNION "QUATERNION_T"
boolean luaL_checkboolean(lua_State *L, int narg);
int LUA_EnumLib(lua_State *L);
......@@ -115,3 +123,7 @@ int LUA_BlockmapLib(lua_State *L);
int LUA_HudLib(lua_State *L);
int LUA_ColorLib(lua_State *L);
int LUA_InputLib(lua_State *L);
int LUA_InterceptLib(lua_State *L);
int LUA_MatrixLib(lua_State *L);
int LUA_QuaternionLib(lua_State *L);
int LUA_VectorLib(lua_State *L);
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -69,6 +69,7 @@ enum sector_e {
sector_triggerer,
sector_friction,
sector_gravity,
sector_customargs
};
static const char *const sector_opt[] = {
......@@ -112,6 +113,7 @@ static const char *const sector_opt[] = {
"triggerer",
"friction",
"gravity",
"customargs",
NULL};
static int sector_fields_ref = LUA_NOREF;
......@@ -147,6 +149,7 @@ enum line_e {
line_taglist,
line_args,
line_stringargs,
line_customargs,
line_sidenum,
line_frontside,
line_backside,
......@@ -173,6 +176,7 @@ static const char *const line_opt[] = {
"taglist",
"args",
"stringargs",
"customargs",
"sidenum",
"frontside",
"backside",
......@@ -213,7 +217,16 @@ enum side_e {
side_sector,
side_special,
side_repeatcnt,
side_text
side_light,
side_light_top,
side_light_mid,
side_light_bottom,
side_lightabsolute,
side_lightabsolute_top,
side_lightabsolute_mid,
side_lightabsolute_bottom,
side_text,
side_customargs
};
static const char *const side_opt[] = {
......@@ -241,7 +254,16 @@ static const char *const side_opt[] = {
"sector",
"special",
"repeatcnt",
"light",
"light_top",
"light_mid",
"light_bottom",
"lightabsolute",
"lightabsolute_top",
"lightabsolute_mid",
"lightabsolute_bottom",
"text",
"customargs",
NULL};
static int side_fields_ref = LUA_NOREF;
......@@ -338,72 +360,6 @@ static const char *const ffloor_opt[] = {
static int ffloor_fields_ref = LUA_NOREF;
#ifdef HAVE_LUA_SEGS
enum seg_e {
seg_valid = 0,
seg_v1,
seg_v2,
seg_side,
seg_offset,
seg_angle,
seg_sidedef,
seg_linedef,
seg_frontsector,
seg_backsector,
seg_polyseg
};
static const char *const seg_opt[] = {
"valid",
"v1",
"v2",
"side",
"offset",
"angle",
"sidedef",
"linedef",
"frontsector",
"backsector",
"polyseg",
NULL};
static int seg_fields_ref = LUA_NOREF;
enum node_e {
node_valid = 0,
node_x,
node_y,
node_dx,
node_dy,
node_bbox,
node_children,
};
static const char *const node_opt[] = {
"valid",
"x",
"y",
"dx",
"dy",
"bbox",
"children",
NULL};
static int node_fields_ref = LUA_NOREF;
enum nodechild_e {
nodechild_valid = 0,
nodechild_right,
nodechild_left,
};
static const char *const nodechild_opt[] = {
"valid",
"right",
"left",
NULL};
#endif
enum bbox_e {
bbox_valid = 0,
bbox_top,
......@@ -444,19 +400,6 @@ static const char *const slope_opt[] = {
static int slope_fields_ref = LUA_NOREF;
// shared by both vector2_t and vector3_t
enum vector_e {
vector_x = 0,
vector_y,
vector_z
};
static const char *const vector_opt[] = {
"x",
"y",
"z",
NULL};
static const char *const array_opt[] ={"iterate",NULL};
static const char *const valid_opt[] ={"valid",NULL};
......@@ -658,6 +601,73 @@ static int sectorlines_num(lua_State *L)
return 1;
}
//////////////////
// customargs_t //
//////////////////
FUNCINLINE static ATTRINLINE int customargs_get(lua_State* L, const char* meta)
{
customargs_t *args = *((customargs_t**)luaL_checkudata(L, 1, meta));
const char* field = luaL_checkstring(L, 2);
if (args == NULL) {
lua_pushnil(L);
return 1;
}
customargs_t* current = args;
while (current != NULL)
{
if (!strcmp(current->name, field))
{
switch (current->type)
{
case UDMF_TYPE_STRING:
lua_pushstring(L, current->value.vstring);
break;
case UDMF_TYPE_NUMERIC:
lua_pushinteger(L, current->value.vint);
break;
case UDMF_TYPE_FIXED:
lua_pushfixed(L, current->value.vfloat);
break;
case UDMF_TYPE_BOOLEAN:
lua_pushboolean(L, current->value.vbool);
break;
default:
lua_pushnil(L);
}
return 1;
}
current = current->next;
}
lua_pushnil(L);
return 1;
}
static int sectorcustomargs_get(lua_State* L)
{
return customargs_get(L, META_SECTORCUSTOMARGS);
}
static int sidecustomargs_get(lua_State* L)
{
return customargs_get(L, META_SIDECUSTOMARGS);
}
static int linecustomargs_get(lua_State* L)
{
return customargs_get(L, META_LINECUSTOMARGS);
}
static int thingcustomargs_get(lua_State* L)
{
return customargs_get(L, META_THINGCUSTOMARGS);
}
//////////////
// sector_t //
//////////////
......@@ -819,6 +829,9 @@ static int sector_get(lua_State *L)
case sector_gravity: // gravity
lua_pushfixed(L, sector->gravity);
return 1;
case sector_customargs:
LUA_PushUserdata(L, sector->customargs, META_SECTORCUSTOMARGS);
return 1;
}
return 0;
}
......@@ -1114,6 +1127,9 @@ static int line_get(lua_State *L)
case line_stringargs:
LUA_PushUserdata(L, line->stringargs, META_LINESTRINGARGS);
return 1;
case line_customargs:
LUA_PushUserdata(L, line->customargs, META_LINECUSTOMARGS);
return 1;
case line_sidenum:
LUA_PushUserdata(L, line->sidenum, META_SIDENUM);
return 1;
......@@ -1311,6 +1327,33 @@ static int side_get(lua_State *L)
case side_repeatcnt:
lua_pushinteger(L, side->repeatcnt);
return 1;
case side_light:
lua_pushinteger(L, side->light);
return 1;
case side_light_top:
lua_pushinteger(L, side->light_top);
return 1;
case side_light_mid:
lua_pushinteger(L, side->light_mid);
return 1;
case side_light_bottom:
lua_pushinteger(L, side->light_bottom);
return 1;
case side_lightabsolute:
lua_pushboolean(L, side->lightabsolute);
return 1;
case side_lightabsolute_top:
lua_pushboolean(L, side->lightabsolute_top);
return 1;
case side_lightabsolute_mid:
lua_pushboolean(L, side->lightabsolute_mid);
return 1;
case side_lightabsolute_bottom:
lua_pushboolean(L, side->lightabsolute_bottom);
return 1;
case side_customargs:
LUA_PushUserdata(L, side->customargs, META_SIDECUSTOMARGS);
return 1;
// TODO: 2.3: Delete
case side_text:
{
......@@ -1330,6 +1373,7 @@ static int side_get(lua_State *L)
return 1;
}
}
return 0;
}
......@@ -1413,6 +1457,30 @@ static int side_set(lua_State *L)
case side_repeatcnt:
side->repeatcnt = luaL_checkinteger(L, 3);
break;
case side_light:
side->light = luaL_checkinteger(L, 3);
break;
case side_light_top:
side->light_top = luaL_checkinteger(L, 3);
break;
case side_light_mid:
side->light_mid = luaL_checkinteger(L, 3);
break;
case side_light_bottom:
side->light_bottom = luaL_checkinteger(L, 3);
break;
case side_lightabsolute:
side->lightabsolute = luaL_checkboolean(L, 3);
break;
case side_lightabsolute_top:
side->lightabsolute_top = luaL_checkboolean(L, 3);
break;
case side_lightabsolute_mid:
side->lightabsolute_mid = luaL_checkboolean(L, 3);
break;
case side_lightabsolute_bottom:
side->lightabsolute_bottom = luaL_checkboolean(L, 3);
break;
}
return 0;
}
......@@ -1476,246 +1544,6 @@ static int vertex_num(lua_State *L)
return 1;
}
#ifdef HAVE_LUA_SEGS
///////////
// seg_t //
///////////
static int seg_get(lua_State *L)
{
seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG));
enum seg_e field = Lua_optoption(L, 2, seg_valid, seg_fields_ref);
if (!seg)
{
if (field == seg_valid) {
lua_pushboolean(L, 0);
return 1;
}
return luaL_error(L, "accessed seg_t doesn't exist anymore.");
}
switch(field)
{
case seg_valid: // valid
lua_pushboolean(L, 1);
return 1;
case seg_v1:
LUA_PushUserdata(L, seg->v1, META_VERTEX);
return 1;
case seg_v2:
LUA_PushUserdata(L, seg->v2, META_VERTEX);
return 1;
case seg_side:
lua_pushinteger(L, seg->side);
return 1;
case seg_offset:
lua_pushfixed(L, seg->offset);
return 1;
case seg_angle:
lua_pushangle(L, seg->angle);
return 1;
case seg_sidedef:
LUA_PushUserdata(L, seg->sidedef, META_SIDE);
return 1;
case seg_linedef:
LUA_PushUserdata(L, seg->linedef, META_LINE);
return 1;
case seg_frontsector:
LUA_PushUserdata(L, seg->frontsector, META_SECTOR);
return 1;
case seg_backsector:
LUA_PushUserdata(L, seg->backsector, META_SECTOR);
return 1;
case seg_polyseg:
LUA_PushUserdata(L, seg->polyseg, META_POLYOBJ);
return 1;
}
return 0;
}
static int seg_num(lua_State *L)
{
seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG));
lua_pushinteger(L, seg-segs);
return 1;
}
////////////
// node_t //
////////////
static int node_get(lua_State *L)
{
node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE));
enum node_e field = Lua_optoption(L, 2, node_valid, node_fields_ref);
if (!node)
{
if (field == node_valid) {
lua_pushboolean(L, 0);
return 1;
}
return luaL_error(L, "accessed node_t doesn't exist anymore.");
}
switch(field)
{
case node_valid: // valid
lua_pushboolean(L, 1);
return 1;
case node_x:
lua_pushfixed(L, node->x);
return 1;
case node_y:
lua_pushfixed(L, node->y);
return 1;
case node_dx:
lua_pushfixed(L, node->x);
return 1;
case node_dy:
lua_pushfixed(L, node->x);
return 1;
case node_bbox:
LUA_PushUserdata(L, node->bbox, META_NODEBBOX);
return 1;
case node_children:
LUA_PushUserdata(L, node->children, META_NODECHILDREN);
return 1;
}
return 0;
}
static int node_num(lua_State *L)
{
node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE));
lua_pushinteger(L, node-nodes);
return 1;
}
///////////////
// node.bbox //
///////////////
/*
// node.bbox[i][j]: i = 0 or 1, j = 0 1 2 or 3
// NOTE: 2D arrays are NOT double pointers,
// the second bbox will be directly after the first in memory (hence the way the bbox is pushed here)
// this function handles the [i] part, bbox_get handles the [j] part
static int nodebbox_get(lua_State *L)
{
fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_NODEBBOX));
int i;
lua_settop(L, 2);
if (!lua_isnumber(L, 2))
{
int field = luaL_checkoption(L, 2, NULL, valid_opt);
if (!bbox)
{
if (field == 0) {
lua_pushboolean(L, 0);
return 1;
}
return luaL_error(L, "accessed node_t doesn't exist anymore.");
} else if (field == 0) {
lua_pushboolean(L, 1);
return 1;
}
}
i = lua_tointeger(L, 2);
if (i < 0 || i > 1)
return 0;
LUA_PushUserdata(L, bbox + i*4*sizeof(fixed_t), META_BBOX);
return 1;
}
*/
static int nodebbox_call(lua_State *L)
{
fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_NODEBBOX));
int i, j;
int n = lua_gettop(L);
if (!bbox)
return luaL_error(L, "accessed node bbox doesn't exist anymore.");
if (n < 3)
return luaL_error(L, "arguments 2 and/or 3 not given (expected node.bbox(child, coord))");
// get child
if (!lua_isnumber(L, 2)) {
enum nodechild_e field = luaL_checkoption(L, 2, nodechild_opt[0], nodechild_opt);
switch (field) {
case nodechild_right: i = 0; break;
case nodechild_left: i = 1; break;
default:
return luaL_error(L, "invalid node child \"%s\".", lua_tostring(L, 2));
}
}
else {
i = lua_tointeger(L, 2);
if (i < 0 || i > 1)
return 0;
}
// get bbox coord
if (!lua_isnumber(L, 3)) {
enum bbox_e field = luaL_checkoption(L, 3, bbox_opt[0], bbox_opt);
switch (field) {
case bbox_top: j = BOXTOP; break;
case bbox_bottom: j = BOXBOTTOM; break;
case bbox_left: j = BOXLEFT; break;
case bbox_right: j = BOXRIGHT; break;
default:
return luaL_error(L, "invalid bbox coordinate \"%s\".", lua_tostring(L, 3));
}
}
else {
j = lua_tointeger(L, 3);
if (j < 0 || j > 3)
return 0;
}
lua_pushinteger(L, bbox[i*4 + j]);
return 1;
}
/////////////////////
// node.children[] //
/////////////////////
// node.children[i]: i = 0 or 1
static int nodechildren_get(lua_State *L)
{
UINT16 *children = *((UINT16 **)luaL_checkudata(L, 1, META_NODECHILDREN));
int i;
lua_settop(L, 2);
if (!lua_isnumber(L, 2))
{
enum nodechild_e field = luaL_checkoption(L, 2, nodechild_opt[0], nodechild_opt);
if (!children)
{
if (field == nodechild_valid) {
lua_pushboolean(L, 0);
return 1;
}
return luaL_error(L, "accessed node_t doesn't exist anymore.");
} else if (field == nodechild_valid) {
lua_pushboolean(L, 1);
return 1;
} else switch (field) {
case nodechild_right: i = 0; break;
case nodechild_left: i = 1; break;
default: return 0;
}
}
else {
i = lua_tointeger(L, 2);
if (i < 0 || i > 1)
return 0;
}
lua_pushinteger(L, children[i]);
return 1;
}
#endif
//////////
// bbox //
//////////
......@@ -1997,113 +1825,6 @@ static int lib_numvertexes(lua_State *L)
return 1;
}
#ifdef HAVE_LUA_SEGS
////////////
// segs[] //
////////////
static int lib_iterateSegs(lua_State *L)
{
size_t i = 0;
INLEVEL
if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call segs.iterate() directly, use it as 'for seg in segs.iterate do <block> end'.");
lua_settop(L, 2);
lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1))
i = (size_t)(*((seg_t **)luaL_checkudata(L, 1, META_SEG)) - segs)+1;
if (i < numsegs)
{
LUA_PushUserdata(L, &segs[i], META_SEG);
return 1;
}
return 0;
}
static int lib_getSeg(lua_State *L)
{
int field;
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
{
size_t i = lua_tointeger(L, 1);
if (i >= numsegs)
return 0;
LUA_PushUserdata(L, &segs[i], META_SEG);
return 1;
}
field = luaL_checkoption(L, 1, NULL, array_opt);
switch(field)
{
case 0: // iterate
lua_pushcfunction(L, lib_iterateSegs);
return 1;
}
return 0;
}
static int lib_numsegs(lua_State *L)
{
lua_pushinteger(L, numsegs);
return 1;
}
/////////////
// nodes[] //
/////////////
static int lib_iterateNodes(lua_State *L)
{
size_t i = 0;
INLEVEL
if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call nodes.iterate() directly, use it as 'for node in nodes.iterate do <block> end'.");
lua_settop(L, 2);
lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1))
i = (size_t)(*((node_t **)luaL_checkudata(L, 1, META_NODE)) - nodes)+1;
if (i < numsegs)
{
LUA_PushUserdata(L, &nodes[i], META_NODE);
return 1;
}
return 0;
}
static int lib_getNode(lua_State *L)
{
int field;
INLEVEL
lua_settop(L, 2);
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
{
size_t i = lua_tointeger(L, 1);
if (i >= numnodes)
return 0;
LUA_PushUserdata(L, &nodes[i], META_NODE);
return 1;
}
field = luaL_checkoption(L, 1, NULL, array_opt);
switch(field)
{
case 0: // iterate
lua_pushcfunction(L, lib_iterateNodes);
return 1;
}
return 0;
}
static int lib_numnodes(lua_State *L)
{
lua_pushinteger(L, numnodes);
return 1;
}
#endif
//////////////
// ffloor_t //
//////////////
......@@ -2648,47 +2369,6 @@ static int slope_set(lua_State *L)
return 0;
}
///////////////
// vector*_t //
///////////////
static int vector2_get(lua_State *L)
{
vector2_t *vec = *((vector2_t **)luaL_checkudata(L, 1, META_VECTOR2));
enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
if (!vec)
return luaL_error(L, "accessed vector2_t doesn't exist anymore.");
switch(field)
{
case vector_x: lua_pushfixed(L, vec->x); return 1;
case vector_y: lua_pushfixed(L, vec->y); return 1;
default: break;
}
return 0;
}
static int vector3_get(lua_State *L)
{
vector3_t *vec = *((vector3_t **)luaL_checkudata(L, 1, META_VECTOR3));
enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
if (!vec)
return luaL_error(L, "accessed vector3_t doesn't exist anymore.");
switch(field)
{
case vector_x: lua_pushfixed(L, vec->x); return 1;
case vector_y: lua_pushfixed(L, vec->y); return 1;
case vector_z: lua_pushfixed(L, vec->z); return 1;
default: break;
}
return 0;
}
/////////////////////
// mapheaderinfo[] //
/////////////////////
......@@ -2997,18 +2677,20 @@ int LUA_MapLib(lua_State *L)
LUA_RegisterUserdataMetatable(L, META_SECTORLINES, sectorlines_get, NULL, sectorlines_num);
LUA_RegisterUserdataMetatable(L, META_SECTOR, sector_get, sector_set, sector_num);
LUA_RegisterUserdataMetatable(L, META_SUBSECTOR, subsector_get, NULL, subsector_num);
LUA_RegisterUserdataMetatable(L, META_SECTORCUSTOMARGS, sectorcustomargs_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_LINE, line_get, NULL, line_num);
LUA_RegisterUserdataMetatable(L, META_LINEARGS, lineargs_get, NULL, lineargs_len);
LUA_RegisterUserdataMetatable(L, META_LINESTRINGARGS, linestringargs_get, NULL, linestringargs_len);
LUA_RegisterUserdataMetatable(L, META_LINECUSTOMARGS, linecustomargs_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_SIDECUSTOMARGS, sidecustomargs_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_SIDENUM, sidenum_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_SIDE, side_get, side_set, side_num);
LUA_RegisterUserdataMetatable(L, META_VERTEX, vertex_get, NULL, vertex_num);
LUA_RegisterUserdataMetatable(L, META_FFLOOR, ffloor_get, ffloor_set, NULL);
LUA_RegisterUserdataMetatable(L, META_BBOX, bbox_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_SLOPE, slope_get, slope_set, NULL);
LUA_RegisterUserdataMetatable(L, META_VECTOR2, vector2_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_VECTOR3, vector3_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_MAPHEADER, mapheaderinfo_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_THINGCUSTOMARGS, thingcustomargs_get, NULL, NULL);
sector_fields_ref = Lua_CreateFieldTable(L, sector_opt);
subsector_fields_ref = Lua_CreateFieldTable(L, subsector_opt);
......@@ -3040,22 +2722,5 @@ int LUA_MapLib(lua_State *L)
&numlines, &lines,
sizeof (line_t), META_LINE);
#ifdef HAVE_LUA_SEGS
LUA_RegisterUserdataMetatable(L, META_SEG, seg_get, NULL, seg_num);
LUA_RegisterUserdataMetatable(L, META_NODE, node_get, NULL, node_num);
LUA_RegisterUserdataMetatable(L, META_NODECHILDREN, nodechildren_get, NULL, NULL);
seg_fields_ref = Lua_CreateFieldTable(L, seg_opt);
node_fields_ref = Lua_CreateFieldTable(L, node_opt);
luaL_newmetatable(L, META_NODEBBOX);
//LUA_SetCFunctionField(L, "__index", nodebbox_get);
LUA_SetCFunctionField(L, "__call", nodebbox_call);
lua_pop(L, 1);
LUA_RegisterGlobalUserdata(L, "segs", lib_getSeg, NULL, lib_numsegs);
LUA_RegisterGlobalUserdata(L, "nodes", lib_getNode, NULL, lib_numnodes);
#endif
return 0;
}
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by LJ Sonic
//
// 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_matrixlib.c
/// \brief matrix library for Lua scripting
#include "matrix.h"
#include "vector3d.h"
#include "lua_script.h"
#include "lua_libs.h"
static vector3_t *GetVector(lua_State *L, int index)
{
vector3_t *vec = lua_touserdata(L, index);
if (!vec)
return NULL;
if (!lua_getmetatable(L, index))
return NULL;
lua_getfield(L, LUA_REGISTRYINDEX, META_VECTOR3);
if (!lua_rawequal(L, -1, -2))
return NULL;
lua_pop(L, 2);
return vec;
}
static void GetVectorOrXYZ(lua_State *L, int index, vector3_t *result)
{
vector3_t *vec = GetVector(L, index);
if (vec)
{
*result = *vec;
}
else
{
result->x = luaL_checkfixed(L, 1);
result->y = luaL_checkfixed(L, 2);
result->z = luaL_checkfixed(L, 3);
}
}
static matrix_t *NewMatrix(lua_State *L)
{
matrix_t *mat = lua_newuserdata(L, sizeof(*mat));
luaL_getmetatable(L, META_MATRIX);
lua_setmetatable(L, -2);
return mat;
}
////////////////////
// STATIC MEMBERS //
////////////////////
static int matrix_new(lua_State *L)
{
Matrix_SetIdentity(NewMatrix(L));
return 1;
}
static int matrix_translation(lua_State *L)
{
vector3_t translation;
GetVectorOrXYZ(L, 1, &translation);
Matrix_SetTranslation(NewMatrix(L), translation.x, translation.y, translation.z);
return 1;
}
static int matrix_scaling(lua_State *L)
{
vector3_t scaling;
GetVectorOrXYZ(L, 1, &scaling);
Matrix_SetScaling(NewMatrix(L), scaling.x, scaling.y, scaling.z);
return 1;
}
static luaL_Reg matrix[] = {
{"new", matrix_new},
{"translation", matrix_translation},
{"scaling", matrix_scaling},
{NULL, NULL}
};
/////////////
// MEMBERS //
/////////////
enum matrixfield_e {
matrixfield_clone = 0,
matrixfield_getvalue,
matrixfield_setvalue,
matrixfield_mulXYZ,
};
static const char *const matrixfield_opt[] = {
"clone",
"get",
"set",
"mulXYZ",
NULL};
static int matrix_clone(lua_State *L)
{
matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX);
Matrix_Copy(NewMatrix(L), mat);
return 1;
}
static int matrix_getvalue(lua_State *L)
{
matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX);
INT32 row = luaL_checkinteger(L, 2);
INT32 col = luaL_checkinteger(L, 3);
if (row < 1 || row > 4)
return luaL_error(L, "matrix row %d out of range (1 - 4)", row);
if (col < 1 || col > 4)
return luaL_error(L, "matrix column %d out of range (1 - 4)", col);
lua_pushfixed(L, mat->matrix[row - 1][col - 1]);
return 1;
}
static int matrix_setvalue(lua_State *L)
{
matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX);
INT32 row = luaL_checkinteger(L, 2);
INT32 col = luaL_checkinteger(L, 3);
fixed_t value = luaL_checkfixed(L, 4);
if (row < 1 || row > 4)
return luaL_error(L, "matrix row %d out of range (1 - 4)", row);
if (col < 1 || col > 4)
return luaL_error(L, "matrix column %d out of range (1 - 4)", col);
mat->matrix[row - 1][col - 1] = value;
return 0;
}
static int matrix_mulXYZ(lua_State *L)
{
matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX);
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
vector3_t vec;
vector3_t result;
Vector3D_Set(&vec, x, y, z);
Matrix_MulVector(&result, mat, &vec);
lua_pushfixed(L, result.x);
lua_pushfixed(L, result.y);
lua_pushfixed(L, result.z);
return 3;
}
static int matrix_get(lua_State *L)
{
enum matrixfield_e field = luaL_checkoption(L, 2, matrixfield_opt[0], matrixfield_opt);
switch(field)
{
case matrixfield_clone: lua_pushcfunction(L, matrix_clone); return 1;
case matrixfield_getvalue: lua_pushcfunction(L, matrix_getvalue); return 1;
case matrixfield_setvalue: lua_pushcfunction(L, matrix_setvalue); return 1;
case matrixfield_mulXYZ: lua_pushcfunction(L, matrix_mulXYZ); return 1;
default: break;
}
return 0;
}
///////////////
// OPERATORS //
///////////////
static int matrix_mul(lua_State *L)
{
matrix_t *mat1 = luaL_checkudata(L, 1, META_MATRIX);
vector3_t *vec2 = GetVector(L, 2);
if (vec2)
{
vector3_t *result = lua_newuserdata(L, sizeof(*result));
luaL_getmetatable(L, META_VECTOR3);
lua_setmetatable(L, -2);
Matrix_MulVector(result, mat1, vec2);
}
else
{
matrix_t *mat2 = luaL_checkudata(L, 2, META_MATRIX);
Matrix_Mul(NewMatrix(L), mat1, mat2);
}
return 1;
}
int LUA_MatrixLib(lua_State *L)
{
luaL_newmetatable(L, META_MATRIX);
LUA_SetCFunctionField(L, "__index", matrix_get);
LUA_SetCFunctionField(L, "__mul", matrix_mul);
lua_pop(L, 1);
luaL_register(L, "Matrix", matrix);
return 0;
}
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -69,6 +69,7 @@ enum mobj_e {
mobj_color,
mobj_translation,
mobj_blendmode,
mobj_alpha,
mobj_bnext,
mobj_bprev,
mobj_hnext,
......@@ -150,6 +151,7 @@ static const char *const mobj_opt[] = {
"color",
"translation",
"blendmode",
"alpha",
"bnext",
"bprev",
"hnext",
......@@ -196,12 +198,12 @@ static int mobj_get(lua_State *L)
enum mobj_e field = Lua_optoption(L, 2, -1, mobj_fields_ref);
lua_settop(L, 2);
if (!mo || !ISINLEVEL) {
if (P_MobjWasRemoved(mo) || !ISINLEVEL) {
if (field == mobj_valid) {
lua_pushboolean(L, 0);
return 1;
}
if (!mo) {
if (P_MobjWasRemoved(mo)) {
return LUA_ErrInvalid(L, "mobj_t");
} else
return luaL_error(L, "Do not access an mobj_t field outside a level!");
......@@ -354,6 +356,9 @@ static int mobj_get(lua_State *L)
case mobj_blendmode:
lua_pushinteger(L, mo->blendmode);
break;
case mobj_alpha:
lua_pushfixed(L, mo->alpha);
break;
case mobj_bnext:
if (mo->blocknode && mo->blocknode->bnext) {
LUA_PushUserdata(L, mo->blocknode->bnext->mobj, META_MOBJ);
......@@ -564,7 +569,7 @@ static int mobj_set(lua_State *L)
mo->frame = (UINT32)luaL_checkinteger(L, 3);
break;
case mobj_sprite2:
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), (UINT8)luaL_checkinteger(L, 3), mo->player);
mo->sprite2 = P_GetSkinSprite2(((skin_t *)mo->skin), (UINT16)luaL_checkinteger(L, 3), mo->player);
break;
case mobj_anim_duration:
mo->anim_duration = (UINT16)luaL_checkinteger(L, 3);
......@@ -733,6 +738,16 @@ static int mobj_set(lua_State *L)
mo->blendmode = blendmode;
break;
}
case mobj_alpha:
{
fixed_t alpha = luaL_checkfixed(L, 3);
if (alpha < 0)
alpha = 0;
else if (alpha > FRACUNIT)
alpha = FRACUNIT;
mo->alpha = alpha;
break;
}
case mobj_bnext:
return NOSETPOS;
case mobj_bprev:
......@@ -762,7 +777,7 @@ static int mobj_set(lua_State *L)
return luaL_error(L, "mobj.type %d out of range (0 - %d).", newtype, NUMMOBJTYPES-1);
mo->type = newtype;
mo->info = &mobjinfo[newtype];
P_SetScale(mo, mo->scale);
P_SetScale(mo, mo->scale, false);
break;
}
case mobj_info:
......@@ -836,9 +851,7 @@ static int mobj_set(lua_State *L)
fixed_t scale = luaL_checkfixed(L, 3);
if (scale < FRACUNIT/100)
scale = FRACUNIT/100;
mo->destscale = scale;
P_SetScale(mo, scale);
mo->old_scale = scale;
P_SetScale(mo, scale, true);
break;
}
case mobj_destscale:
......@@ -960,6 +973,7 @@ enum mapthing_e {
mapthing_taglist,
mapthing_args,
mapthing_stringargs,
mapthing_customargs,
mapthing_mobj,
};
......@@ -981,6 +995,7 @@ const char *const mapthing_opt[] = {
"taglist",
"args",
"stringargs",
"customargs",
"mobj",
NULL,
};
......@@ -1059,6 +1074,9 @@ static int mapthing_get(lua_State *L)
case mapthing_stringargs:
LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS);
break;
case mapthing_customargs:
LUA_PushUserdata(L, mt->customargs, META_THINGCUSTOMARGS);
break;
case mapthing_mobj:
LUA_PushUserdata(L, mt->mobj, META_MOBJ);
break;
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -190,6 +190,7 @@ enum player_e
player_marelap,
player_marebonuslap,
player_marebegunat,
player_lastmaretime,
player_startedtime,
player_finishedtime,
player_lapbegunat,
......@@ -225,6 +226,7 @@ enum player_e
player_quittime,
player_lastinputtime,
player_ping,
player_muted,
player_fovadd
};
......@@ -337,6 +339,7 @@ static const char *const player_opt[] = {
"marelap",
"marebonuslap",
"marebegunat",
"lastmaretime",
"startedtime",
"finishedtime",
"lapbegunat",
......@@ -372,6 +375,7 @@ static const char *const player_opt[] = {
"quittime",
"lastinputtime",
"ping",
"muted",
"fovadd",
NULL,
};
......@@ -725,6 +729,9 @@ static int player_get(lua_State *L)
case player_marebegunat:
lua_pushinteger(L, plr->marebegunat);
break;
case player_lastmaretime:
lua_pushinteger(L, plr->lastmaretime);
break;
case player_startedtime:
lua_pushinteger(L, plr->startedtime);
break;
......@@ -830,6 +837,9 @@ static int player_get(lua_State *L)
case player_ping:
lua_pushinteger(L, playerpingtable[plr - players]);
break;
case player_muted:
lua_pushboolean(L, plr->muted);
break;
case player_fovadd:
lua_pushfixed(L, plr->fovadd);
break;
......@@ -1219,6 +1229,9 @@ static int player_set(lua_State *L)
case player_marebegunat:
plr->marebegunat = (tic_t)luaL_checkinteger(L, 3);
break;
case player_lastmaretime:
plr->lastmaretime = (tic_t)luaL_checkinteger(L, 3);
break;
case player_startedtime:
plr->startedtime = (tic_t)luaL_checkinteger(L, 3);
break;
......@@ -1351,6 +1364,11 @@ static int player_set(lua_State *L)
case player_lastinputtime:
plr->lastinputtime = (tic_t)luaL_checkinteger(L, 3);
break;
case player_ping:
return NOSET;
case player_muted:
plr->muted = lua_toboolean(L, 3);
break;
case player_fovadd:
plr->fovadd = luaL_checkfixed(L, 3);
break;
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by LJ Sonic
//
// 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_quaternionlib.c
/// \brief quaternion library for Lua scripting
#include "quaternion.h"
#include "lua_script.h"
#include "lua_libs.h"
static quaternion_t *NewQuaternion(lua_State *L)
{
quaternion_t *quat = lua_newuserdata(L, sizeof(*quat));
luaL_getmetatable(L, META_QUATERNION);
lua_setmetatable(L, -2);
return quat;
}
////////////////////
// STATIC MEMBERS //
////////////////////
static int quaternion_new(lua_State *L)
{
Quaternion_SetIdentity(NewQuaternion(L));
return 1;
}
static int quaternion_fromAxisRotation(lua_State *L)
{
vector3_t *axis = luaL_checkudata(L, 1, META_VECTOR3);
fixed_t angle = luaL_checkfixed(L, 2);
Quaternion_SetAxisRotation(NewQuaternion(L), axis, angle);
return 1;
}
static luaL_Reg quaternion[] = {
{"new", quaternion_new},
{"fromAxisRotation", quaternion_fromAxisRotation},
{NULL, NULL}
};
/////////////
// MEMBERS //
/////////////
static int quaternion_clone(lua_State *L)
{
quaternion_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
Quaternion_Copy(NewQuaternion(L), quat);
return 1;
}
static int quaternion_toMatrix(lua_State *L)
{
quaternion_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
matrix_t *mat = lua_newuserdata(L, sizeof(*mat));
luaL_getmetatable(L, META_MATRIX);
lua_setmetatable(L, -2);
Quaternion_ToMatrix(mat, quat);
return 1;
}
enum quaternionfield_e {
quaternionfield_clone = 0,
quaternionfield_toMatrix,
quaternionfield_x,
quaternionfield_y,
quaternionfield_z,
quaternionfield_w,
};
static const char *const quaternionfield_opt[] = {
"clone",
"toMatrix",
"x",
"y",
"z",
"w",
NULL};
static int quaternion_get(lua_State *L)
{
quaternion_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
enum quaternionfield_e field = luaL_checkoption(L, 2, quaternionfield_opt[0], quaternionfield_opt);
switch(field)
{
case quaternionfield_clone: lua_pushcfunction(L, quaternion_clone); return 1;
case quaternionfield_toMatrix: lua_pushcfunction(L, quaternion_toMatrix); return 1;
case quaternionfield_x: lua_pushfixed(L, quat->x); return 1;
case quaternionfield_y: lua_pushfixed(L, quat->y); return 1;
case quaternionfield_z: lua_pushfixed(L, quat->z); return 1;
case quaternionfield_w: lua_pushfixed(L, quat->w); return 1;
default: break;
}
return 0;
}
///////////////
// OPERATORS //
///////////////
static int quaternion_mul(lua_State *L)
{
quaternion_t *quat1 = luaL_checkudata(L, 1, META_QUATERNION);
quaternion_t *quat2 = luaL_checkudata(L, 2, META_QUATERNION);
Quaternion_Mul(NewQuaternion(L), quat1, quat2);
return 1;
}
int LUA_QuaternionLib(lua_State *L)
{
luaL_newmetatable(L, META_QUATERNION);
LUA_SetCFunctionField(L, "__index", quaternion_get);
LUA_SetCFunctionField(L, "__mul", quaternion_mul);
lua_pop(L, 1);
luaL_register(L, "Quaternion", quaternion);
return 0;
}
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -20,6 +20,7 @@
#include "r_state.h"
#include "r_sky.h"
#include "g_game.h"
#include "g_demo.h"
#include "g_input.h"
#include "f_finale.h"
#include "byteptr.h"
......@@ -62,6 +63,10 @@ static lua_CFunction liblist[] = {
LUA_HudLib, // HUD stuff
LUA_ColorLib, // general color functions
LUA_InputLib, // inputs
LUA_InterceptLib, // intercept_t
LUA_VectorLib, // vectors
LUA_MatrixLib, // matrices
LUA_QuaternionLib, // quaternions
NULL
};
......@@ -274,6 +279,18 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"tutorialmode")) {
lua_pushboolean(L, tutorialmode);
return 1;
} else if (fastcmp(word,"keepcutscene")) {
lua_pushboolean(L, keepcutscene);
return 1;
} else if (fastcmp(word,"nextgametype")) {
lua_pushinteger(L, nextgametype);
return 1;
} else if (fastcmp(word,"skipstats")) {
lua_pushinteger(L, skipstats);
return 1;
} else if (fastcmp(word,"nextmapoverride")) {
lua_pushinteger(L, nextmapoverride);
return 1;
// end map vars
// begin CTF colors
} else if (fastcmp(word,"skincolor_redteam")) {
......@@ -394,6 +411,22 @@ int LUA_PushGlobals(lua_State *L, const char *word)
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
// demos booleans
} else if (fastcmp(word, "demoplayback")) {
lua_pushboolean(L, demoplayback);
return 1;
} else if (fastcmp(word, "titledemo")) {
lua_pushboolean(L, titledemo);
return 1;
} else if (fastcmp(word, "demorecording")) {
lua_pushboolean(L, demorecording);
return 1;
} else if (fastcmp(word, "timingdemo")) {
lua_pushboolean(L, timingdemo);
return 1;
} else if (fastcmp(word, "demosynced")) {
lua_pushboolean(L, demosynced);
return 1;
} else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds);
return 1;
......@@ -412,6 +445,18 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "token")) {
lua_pushinteger(L, token);
return 1;
} else if (fastcmp(word, "emblems")) {
lua_pushinteger(L, M_CountEmblems(clientGamedata));
return 1;
} else if (fastcmp(word, "numemblems")) {
lua_pushinteger(L, numemblems);
return 1;
} else if (fastcmp(word, "numextraemblems")) {
lua_pushinteger(L, numextraemblems);
return 1;
} else if (fastcmp(word, "nummaprings")) {
lua_pushinteger(L, nummaprings);
return 1;
} else if (fastcmp(word, "gamestate")) {
lua_pushinteger(L, gamestate);
return 1;
......@@ -437,6 +482,14 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "chatactive")) {
lua_pushboolean(L, chat_on);
return 1;
} else if (fastcmp(word, "currentsaveslot")) {
if (multiplayer)
return 0;
lua_pushinteger(L, cursaveslot);
return 1;
} else if (fastcmp(word, "gamedatafilename")) {
lua_pushstring(L, strcmp(timeattackfolder, "main") ? timeattackfolder : "gamedata");
return 1;
}
return 0;
}
......@@ -460,6 +513,8 @@ int LUA_CheckGlobals(lua_State *L, const char *word)
emeralds = (UINT16)luaL_checkinteger(L, 2);
else if (fastcmp(word, "token"))
token = (UINT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "nummaprings"))
nummaprings = (INT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "gravity"))
gravity = (fixed_t)luaL_checkinteger(L, 2);
else if (fastcmp(word, "stoppedclock"))
......@@ -622,9 +677,6 @@ static inline boolean LUA_LoadFile(MYFILE *f, char *name)
if (!gL) // Lua needs to be initialized
LUA_ClearState();
lua_pushinteger(gL, f->wad);
lua_setfield(gL, LUA_REGISTRYINDEX, "WAD");
lua_pushcfunction(gL, LUA_GetErrorMessage);
errorhandlerindex = lua_gettop(gL);
......@@ -980,16 +1032,6 @@ void LUA_InvalidateLevel(void)
LUA_InvalidateUserdata(&slope->o);
LUA_InvalidateUserdata(&slope->d);
}
#ifdef HAVE_LUA_SEGS
for (i = 0; i < numsegs; i++)
LUA_InvalidateUserdata(&segs[i]);
for (i = 0; i < numnodes; i++)
{
LUA_InvalidateUserdata(&nodes[i]);
LUA_InvalidateUserdata(nodes[i].bbox);
LUA_InvalidateUserdata(nodes[i].children);
}
#endif
}
void LUA_InvalidateMapthings(void)
......@@ -1016,743 +1058,6 @@ void LUA_InvalidatePlayer(player_t *player)
LUA_InvalidateUserdata(&player->cmd);
}
enum
{
ARCH_NULL=0,
ARCH_TRUE,
ARCH_FALSE,
ARCH_INT8,
ARCH_INT16,
ARCH_INT32,
ARCH_SMALLSTRING,
ARCH_LARGESTRING,
ARCH_TABLE,
ARCH_MOBJINFO,
ARCH_STATE,
ARCH_MOBJ,
ARCH_PLAYER,
ARCH_MAPTHING,
ARCH_VERTEX,
ARCH_LINE,
ARCH_SIDE,
ARCH_SUBSECTOR,
ARCH_SECTOR,
#ifdef HAVE_LUA_SEGS
ARCH_SEG,
ARCH_NODE,
#endif
ARCH_FFLOOR,
ARCH_POLYOBJ,
ARCH_SLOPE,
ARCH_MAPHEADER,
ARCH_SKINCOLOR,
ARCH_MOUSE,
ARCH_SKIN,
ARCH_TEND=0xFF,
};
static const struct {
const char *meta;
UINT8 arch;
} meta2arch[] = {
{META_MOBJINFO, ARCH_MOBJINFO},
{META_STATE, ARCH_STATE},
{META_MOBJ, ARCH_MOBJ},
{META_PLAYER, ARCH_PLAYER},
{META_MAPTHING, ARCH_MAPTHING},
{META_VERTEX, ARCH_VERTEX},
{META_LINE, ARCH_LINE},
{META_SIDE, ARCH_SIDE},
{META_SUBSECTOR,ARCH_SUBSECTOR},
{META_SECTOR, ARCH_SECTOR},
#ifdef HAVE_LUA_SEGS
{META_SEG, ARCH_SEG},
{META_NODE, ARCH_NODE},
#endif
{META_FFLOOR, ARCH_FFLOOR},
{META_POLYOBJ, ARCH_POLYOBJ},
{META_SLOPE, ARCH_SLOPE},
{META_MAPHEADER, ARCH_MAPHEADER},
{META_SKINCOLOR, ARCH_SKINCOLOR},
{META_MOUSE, ARCH_MOUSE},
{META_SKIN, ARCH_SKIN},
{NULL, ARCH_NULL}
};
static UINT8 GetUserdataArchType(int index)
{
UINT8 i;
lua_getmetatable(gL, index);
for (i = 0; meta2arch[i].meta; i++)
{
luaL_getmetatable(gL, meta2arch[i].meta);
if (lua_rawequal(gL, -1, -2))
{
lua_pop(gL, 2);
return meta2arch[i].arch;
}
lua_pop(gL, 1);
}
lua_pop(gL, 1);
return ARCH_NULL;
}
static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{
if (myindex < 0)
myindex = lua_gettop(gL)+1+myindex;
switch (lua_type(gL, myindex))
{
case LUA_TNONE:
case LUA_TNIL:
WRITEUINT8(save_p, ARCH_NULL);
break;
// This might be a problem. D:
case LUA_TLIGHTUSERDATA:
case LUA_TTHREAD:
case LUA_TFUNCTION:
WRITEUINT8(save_p, ARCH_NULL);
return 2;
case LUA_TBOOLEAN:
WRITEUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE);
break;
case LUA_TNUMBER:
{
lua_Integer number = lua_tointeger(gL, myindex);
if (number >= INT8_MIN && number <= INT8_MAX)
{
WRITEUINT8(save_p, ARCH_INT8);
WRITESINT8(save_p, number);
}
else if (number >= INT16_MIN && number <= INT16_MAX)
{
WRITEUINT8(save_p, ARCH_INT16);
WRITEINT16(save_p, number);
}
else
{
WRITEUINT8(save_p, ARCH_INT32);
WRITEFIXED(save_p, number);
}
break;
}
case LUA_TSTRING:
{
UINT32 len = (UINT32)lua_objlen(gL, myindex); // get length of string, including embedded zeros
const char *s = lua_tostring(gL, myindex);
UINT32 i = 0;
// if you're wondering why we're writing a string to save_p this way,
// it turns out that Lua can have embedded zeros ('\0') in the strings,
// so we can't use WRITESTRING as that cuts off when it finds a '\0'.
// Saving the size of the string also allows us to get the size of the string on the other end,
// fixing the awful crashes previously encountered for reading strings longer than 1024
// (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?)
// -- Monster Iestyn 05/08/18
if (len < 255)
{
WRITEUINT8(save_p, ARCH_SMALLSTRING);
WRITEUINT8(save_p, len); // save size of string
}
else
{
WRITEUINT8(save_p, ARCH_LARGESTRING);
WRITEUINT32(save_p, len); // save size of string
}
while (i < len)
WRITECHAR(save_p, s[i++]); // write chars individually, including the embedded zeros
break;
}
case LUA_TTABLE:
{
boolean found = false;
INT32 i;
UINT16 t = (UINT16)lua_objlen(gL, TABLESINDEX);
for (i = 1; i <= t && !found; i++)
{
lua_rawgeti(gL, TABLESINDEX, i);
if (lua_rawequal(gL, myindex, -1))
{
t = i;
found = true;
}
lua_pop(gL, 1);
}
if (!found)
{
t++;
if (t == 0)
{
CONS_Alert(CONS_ERROR, "Too many tables to archive!\n");
WRITEUINT8(save_p, ARCH_NULL);
return 0;
}
}
WRITEUINT8(save_p, ARCH_TABLE);
WRITEUINT16(save_p, t);
if (!found)
{
lua_pushvalue(gL, myindex);
lua_rawseti(gL, TABLESINDEX, t);
return 1;
}
break;
}
case LUA_TUSERDATA:
switch (GetUserdataArchType(myindex))
{
case ARCH_MOBJINFO:
{
mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOBJINFO);
WRITEUINT16(save_p, info - mobjinfo);
break;
}
case ARCH_STATE:
{
state_t *state = *((state_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_STATE);
WRITEUINT16(save_p, state - states);
break;
}
case ARCH_MOBJ:
{
mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex));
if (!mobj)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_MOBJ);
WRITEUINT32(save_p, mobj->mobjnum);
}
break;
}
case ARCH_PLAYER:
{
player_t *player = *((player_t **)lua_touserdata(gL, myindex));
if (!player)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_PLAYER);
WRITEUINT8(save_p, player - players);
}
break;
}
case ARCH_MAPTHING:
{
mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex));
if (!mapthing)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_MAPTHING);
WRITEUINT16(save_p, mapthing - mapthings);
}
break;
}
case ARCH_VERTEX:
{
vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex));
if (!vertex)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_VERTEX);
WRITEUINT16(save_p, vertex - vertexes);
}
break;
}
case ARCH_LINE:
{
line_t *line = *((line_t **)lua_touserdata(gL, myindex));
if (!line)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_LINE);
WRITEUINT16(save_p, line - lines);
}
break;
}
case ARCH_SIDE:
{
side_t *side = *((side_t **)lua_touserdata(gL, myindex));
if (!side)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SIDE);
WRITEUINT16(save_p, side - sides);
}
break;
}
case ARCH_SUBSECTOR:
{
subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex));
if (!subsector)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SUBSECTOR);
WRITEUINT16(save_p, subsector - subsectors);
}
break;
}
case ARCH_SECTOR:
{
sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex));
if (!sector)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SECTOR);
WRITEUINT16(save_p, sector - sectors);
}
break;
}
#ifdef HAVE_LUA_SEGS
case ARCH_SEG:
{
seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex));
if (!seg)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SEG);
WRITEUINT16(save_p, seg - segs);
}
break;
}
case ARCH_NODE:
{
node_t *node = *((node_t **)lua_touserdata(gL, myindex));
if (!node)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_NODE);
WRITEUINT16(save_p, node - nodes);
}
break;
}
#endif
case ARCH_FFLOOR:
{
ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex));
if (!rover)
WRITEUINT8(save_p, ARCH_NULL);
else {
UINT16 i = P_GetFFloorID(rover);
if (i == UINT16_MAX) // invalid ID
WRITEUINT8(save_p, ARCH_NULL);
else
{
WRITEUINT8(save_p, ARCH_FFLOOR);
WRITEUINT16(save_p, rover->target - sectors);
WRITEUINT16(save_p, i);
}
}
break;
}
case ARCH_POLYOBJ:
{
polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex));
if (!polyobj)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_POLYOBJ);
WRITEUINT16(save_p, polyobj-PolyObjects);
}
break;
}
case ARCH_SLOPE:
{
pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex));
if (!slope)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SLOPE);
WRITEUINT16(save_p, slope->id);
}
break;
}
case ARCH_MAPHEADER:
{
mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
if (!header)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_MAPHEADER);
WRITEUINT16(save_p, header - *mapheaderinfo);
}
break;
}
case ARCH_SKINCOLOR:
{
skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKINCOLOR);
WRITEUINT16(save_p, info - skincolors);
break;
}
case ARCH_MOUSE:
{
mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOUSE);
WRITEUINT8(save_p, m == &mouse ? 1 : 2);
break;
}
case ARCH_SKIN:
{
skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKIN);
WRITEUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256
break;
}
default:
WRITEUINT8(save_p, ARCH_NULL);
return 2;
}
break;
}
return 0;
}
static void ArchiveExtVars(void *pointer, const char *ptype)
{
int TABLESINDEX;
UINT16 i;
if (!gL) {
if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0);
return;
}
TABLESINDEX = lua_gettop(gL);
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(gL, -1));
lua_pushlightuserdata(gL, pointer);
lua_rawget(gL, -2);
lua_remove(gL, -2); // pop LREG_EXTVARS
if (!lua_istable(gL, -1))
{ // no extra values table
lua_pop(gL, 1);
if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0);
return;
}
lua_pushnil(gL);
for (i = 0; lua_next(gL, -2); i++)
lua_pop(gL, 1);
// skip anything that has an empty table and isn't a player.
if (i == 0)
{
if (fastcmp(ptype,"player")) // always include players even if they have no extra variables
WRITEUINT16(save_p, 0);
lua_pop(gL, 1);
return;
}
if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header
WRITEUINT32(save_p, ((mobj_t *)pointer)->mobjnum);
WRITEUINT16(save_p, i);
lua_pushnil(gL);
while (lua_next(gL, -2))
{
I_Assert(lua_type(gL, -2) == LUA_TSTRING);
WRITESTRING(save_p, lua_tostring(gL, -2));
if (ArchiveValue(TABLESINDEX, -1) == 2)
CONS_Alert(CONS_ERROR, "Type of value for %s entry '%s' (%s) could not be archived!\n", ptype, lua_tostring(gL, -2), luaL_typename(gL, -1));
lua_pop(gL, 1);
}
lua_pop(gL, 1);
}
static int NetArchive(lua_State *L)
{
int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L);
for (i = 1; i <= n; i++)
ArchiveValue(TABLESINDEX, i);
return n;
}
static void ArchiveTables(void)
{
int TABLESINDEX;
UINT16 i, n;
UINT8 e;
if (!gL)
return;
TABLESINDEX = lua_gettop(gL);
n = (UINT16)lua_objlen(gL, TABLESINDEX);
for (i = 1; i <= n; i++)
{
lua_rawgeti(gL, TABLESINDEX, i);
lua_pushnil(gL);
while (lua_next(gL, -2))
{
// Write key
e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
if (e == 1)
n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise)
CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -2), luaL_typename(gL, -2), i);
// Write value
e = ArchiveValue(TABLESINDEX, -1);
if (e == 1)
n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid value type
CONS_Alert(CONS_ERROR, "Type of value for table %d entry '%s' (%s) could not be archived!\n", i, lua_tostring(gL, -2), luaL_typename(gL, -1));
lua_pop(gL, 1);
}
WRITEUINT8(save_p, ARCH_TEND);
// Write metatable ID
if (lua_getmetatable(gL, -1))
{
// registry.metatables[metatable]
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_pushvalue(gL, -2);
lua_gettable(gL, -2);
WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1));
lua_pop(gL, 3);
}
else
WRITEUINT16(save_p, 0);
lua_pop(gL, 1);
}
}
static UINT8 UnArchiveValue(int TABLESINDEX)
{
UINT8 type = READUINT8(save_p);
switch (type)
{
case ARCH_NULL:
lua_pushnil(gL);
break;
case ARCH_TRUE:
lua_pushboolean(gL, true);
break;
case ARCH_FALSE:
lua_pushboolean(gL, false);
break;
case ARCH_INT8:
lua_pushinteger(gL, READSINT8(save_p));
break;
case ARCH_INT16:
lua_pushinteger(gL, READINT16(save_p));
break;
case ARCH_INT32:
lua_pushinteger(gL, READFIXED(save_p));
break;
case ARCH_SMALLSTRING:
case ARCH_LARGESTRING:
{
UINT32 len;
char *value;
UINT32 i = 0;
// See my comments in the ArchiveValue function;
// it's much the same for reading strings as writing them!
// (i.e. we can't use READSTRING either)
// -- Monster Iestyn 05/08/18
if (type == ARCH_SMALLSTRING)
len = READUINT8(save_p); // length of string, including embedded zeros
else
len = READUINT32(save_p); // length of string, including embedded zeros
value = malloc(len); // make temp buffer of size len
// now read the actual string
while (i < len)
value[i++] = READCHAR(save_p); // read chars individually, including the embedded zeros
lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros)
free(value); // free the buffer
break;
}
case ARCH_TABLE:
{
UINT16 tid = READUINT16(save_p);
lua_rawgeti(gL, TABLESINDEX, tid);
if (lua_isnil(gL, -1))
{
lua_pop(gL, 1);
lua_newtable(gL);
lua_pushvalue(gL, -1);
lua_rawseti(gL, TABLESINDEX, tid);
return 2;
}
break;
}
case ARCH_MOBJINFO:
LUA_PushUserdata(gL, &mobjinfo[READUINT16(save_p)], META_MOBJINFO);
break;
case ARCH_STATE:
LUA_PushUserdata(gL, &states[READUINT16(save_p)], META_STATE);
break;
case ARCH_MOBJ:
LUA_PushUserdata(gL, P_FindNewPosition(READUINT32(save_p)), META_MOBJ);
break;
case ARCH_PLAYER:
LUA_PushUserdata(gL, &players[READUINT8(save_p)], META_PLAYER);
break;
case ARCH_MAPTHING:
LUA_PushUserdata(gL, &mapthings[READUINT16(save_p)], META_MAPTHING);
break;
case ARCH_VERTEX:
LUA_PushUserdata(gL, &vertexes[READUINT16(save_p)], META_VERTEX);
break;
case ARCH_LINE:
LUA_PushUserdata(gL, &lines[READUINT16(save_p)], META_LINE);
break;
case ARCH_SIDE:
LUA_PushUserdata(gL, &sides[READUINT16(save_p)], META_SIDE);
break;
case ARCH_SUBSECTOR:
LUA_PushUserdata(gL, &subsectors[READUINT16(save_p)], META_SUBSECTOR);
break;
case ARCH_SECTOR:
LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_SECTOR);
break;
#ifdef HAVE_LUA_SEGS
case ARCH_SEG:
LUA_PushUserdata(gL, &segs[READUINT16(save_p)], META_SEG);
break;
case ARCH_NODE:
LUA_PushUserdata(gL, &nodes[READUINT16(save_p)], META_NODE);
break;
#endif
case ARCH_FFLOOR:
{
sector_t *sector = &sectors[READUINT16(save_p)];
UINT16 id = READUINT16(save_p);
ffloor_t *rover = P_GetFFloorByID(sector, id);
if (rover)
LUA_PushUserdata(gL, rover, META_FFLOOR);
break;
}
case ARCH_POLYOBJ:
LUA_PushUserdata(gL, &PolyObjects[READUINT16(save_p)], META_POLYOBJ);
break;
case ARCH_SLOPE:
LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE);
break;
case ARCH_MAPHEADER:
LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER);
break;
case ARCH_SKINCOLOR:
LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR);
break;
case ARCH_MOUSE:
LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE);
break;
case ARCH_SKIN:
LUA_PushUserdata(gL, skins[READUINT8(save_p)], META_SKIN);
break;
case ARCH_TEND:
return 1;
}
return 0;
}
static void UnArchiveExtVars(void *pointer)
{
int TABLESINDEX;
UINT16 field_count = READUINT16(save_p);
UINT16 i;
char field[1024];
if (field_count == 0)
return;
I_Assert(gL != NULL);
TABLESINDEX = lua_gettop(gL);
lua_createtable(gL, 0, field_count); // pointer's ext vars subtable
for (i = 0; i < field_count; i++)
{
READSTRING(save_p, field);
UnArchiveValue(TABLESINDEX);
lua_setfield(gL, -2, field);
}
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(gL, -1));
lua_pushlightuserdata(gL, pointer);
lua_pushvalue(gL, -3); // pointer's ext vars subtable
lua_rawset(gL, -3);
lua_pop(gL, 2); // pop LREG_EXTVARS and pointer's subtable
}
static int NetUnArchive(lua_State *L)
{
int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L);
for (i = 1; i <= n; i++)
UnArchiveValue(TABLESINDEX);
return n;
}
static void UnArchiveTables(void)
{
int TABLESINDEX;
UINT16 i, n;
UINT16 metatableid;
if (!gL)
return;
TABLESINDEX = lua_gettop(gL);
n = (UINT16)lua_objlen(gL, TABLESINDEX);
for (i = 1; i <= n; i++)
{
lua_rawgeti(gL, TABLESINDEX, i);
while (true)
{
UINT8 e = UnArchiveValue(TABLESINDEX); // read key
if (e == 1) // End of table
break;
else if (e == 2) // Key contains a new table
n++;
if (UnArchiveValue(TABLESINDEX) == 2) // read value
n++;
if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved)
{
CONS_Alert(CONS_ERROR, "A nil key in table %d was found! (Invalid key type or corrupted save?)\n", i);
lua_pop(gL, 2); // pop key and value instead of setting them in the table, to prevent Lua panic errors
}
else
lua_rawset(gL, -3);
}
metatableid = READUINT16(save_p);
if (metatableid)
{
// setmetatable(table, registry.metatables[metatableid])
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_rawgeti(gL, -1, metatableid);
if (lua_isnil(gL, -1))
I_Error("Unknown metatable ID %d\n", metatableid);
lua_setmetatable(gL, -3);
lua_pop(gL, 1);
}
lua_pop(gL, 1);
}
}
void LUA_Step(void)
{
if (!gL)
......@@ -1761,76 +1066,6 @@ void LUA_Step(void)
lua_gc(gL, LUA_GCSTEP, 1);
}
void LUA_Archive(void)
{
INT32 i;
thinker_t *th;
if (gL)
lua_newtable(gL); // tables to be archived.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] && i > 0) // dedicated servers...
continue;
// all players in game will be archived, even if they just add a 0.
ArchiveExtVars(&players[i], "player");
}
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
// archive function will determine when to skip mobjs,
// and write mobjnum in otherwise.
ArchiveExtVars(th, "mobj");
}
WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode
ArchiveTables();
if (gL)
lua_pop(gL, 1); // pop tables
}
void LUA_UnArchive(void)
{
UINT32 mobjnum;
INT32 i;
thinker_t *th;
if (gL)
lua_newtable(gL); // tables to be read
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] && i > 0) // dedicated servers...
continue;
UnArchiveExtVars(&players[i]);
}
do {
mobjnum = READUINT32(save_p); // read a mobjnum
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
continue;
UnArchiveExtVars(th); // apply variables
}
} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode
UnArchiveTables();
if (gL)
lua_pop(gL, 1); // pop tables
}
// For mobj_t, player_t, etc. to take custom variables.
int Lua_optoption(lua_State *L, int narg, int def, int list_ref)
{
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -13,6 +13,7 @@
#ifndef LUA_SCRIPT_H
#define LUA_SCRIPT_H
#include "p_saveg.h"
#include "m_fixed.h"
#include "doomtype.h"
#include "d_player.h"
......@@ -29,7 +30,9 @@
// fixed_t casting
// TODO add some distinction between fixed numbers and integer numbers
// for at least the purpose of printing and maybe math.
#define lua_tofixed(L, i) lua_tointeger(L, i)
#define luaL_checkfixed(L, i) luaL_checkinteger(L, i)
#define luaL_optfixed(L, i, d) luaL_optinteger(L, i, d)
#define lua_pushfixed(L, f) lua_pushinteger(L, f)
// angle_t casting
......@@ -52,15 +55,12 @@ void LUA_DumpFile(const char *filename);
#endif
fixed_t LUA_EvalMath(const char *word);
void LUA_Step(void);
void LUA_Archive(void);
void LUA_UnArchive(void);
int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_CheckGlobals(lua_State *L, const char *word);
void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
void LUA_CVarChanged(void *cvar); // lua_consolelib.c
int Lua_optoption(lua_State *L, int narg, int def, int list_ref);
int Lua_CreateFieldTable(lua_State *L, const char *const lst[]);
void LUA_HookNetArchive(lua_CFunction archFunc);
void LUA_PushTaggableObjectArray
( lua_State *L,
......@@ -162,9 +162,6 @@ void COM_Lua_f(void);
}\
}
// uncomment if you want seg_t/node_t in Lua
// #define HAVE_LUA_SEGS
#define ISINLEVEL \
(gamestate == GS_LEVEL || titlemapinaction)
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2014-2016 by John "JTE" Muniz.
// Copyright (C) 2014-2023 by Sonic Team Junior.
// Copyright (C) 2014-2025 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -54,7 +54,9 @@ enum skin {
skin_contspeed,
skin_contangle,
skin_soundsid,
skin_sprites,
skin_sprites, // TODO: 2.3: Delete
skin_skinsprites,
skin_supersprites,
skin_natkcolor
};
......@@ -94,7 +96,9 @@ static const char *const skin_opt[] = {
"contspeed",
"contangle",
"soundsid",
"sprites",
"sprites", // TODO: 2.3: Delete
"skinsprites",
"supersprites",
"natkcolor",
NULL};
......@@ -217,9 +221,15 @@ static int skin_get(lua_State *L)
case skin_soundsid:
LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID);
break;
case skin_sprites:
case skin_sprites: // TODO: 2.3: Delete
LUA_PushUserdata(L, skin->sprites_compat, META_SKINSPRITESCOMPAT);
break;
case skin_skinsprites:
LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
break;
case skin_supersprites:
LUA_PushUserdata(L, skin->super.sprites, META_SKINSPRITES);
break;
case skin_natkcolor:
lua_pushinteger(L, skin->natkcolor);
break;
......@@ -333,34 +343,59 @@ static int soundsid_num(lua_State *L)
return 1;
}
enum spritesopt {
numframes = 0
};
static const char *const sprites_opt[] = {
"numframes",
NULL};
// skin.sprites[i] -> sprites[i]
// skin.skinsprites[i] -> sprites[i]
static int lib_getSkinSprite(lua_State *L)
{
spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES);
playersprite_t i = luaL_checkinteger(L, 2);
if (i < 0 || i >= NUMPLAYERSPRITES)
return luaL_error(L, "skin sprites index %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1);
LUA_PushUserdata(L, &sksprites[i], META_SKINSPRITESLIST);
return 1;
}
// #skin.skinsprites -> NUMPLAYERSPRITES
static int lib_numSkinsSprites(lua_State *L)
{
lua_pushinteger(L, NUMPLAYERSPRITES);
return 1;
}
// TODO: 2.3: Delete
// skin.sprites[i] -> sprites[i]
static int lib_getSkinSpriteCompat(lua_State *L)
{
spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESCOMPAT);
INT32 i = luaL_checkinteger(L, 2) & (SPR2F_MASK | SPR2F_SUPER);
if (i & SPR2F_SUPER)
i = (i & ~SPR2F_SUPER) + NUMPLAYERSPRITES;
if (i < 0 || i >= NUMPLAYERSPRITES*2)
return luaL_error(L, LUA_QL("skin_t") " field 'sprites' index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1);
return luaL_error(L, "skin sprites index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1);
LUA_PushUserdata(L, &sksprites[i], META_SKINSPRITESLIST);
return 1;
}
// TODO: 2.3: Delete
// #skin.sprites -> NUMPLAYERSPRITES*2
static int lib_numSkinsSprites(lua_State *L)
static int lib_numSkinsSpritesCompat(lua_State *L)
{
lua_pushinteger(L, NUMPLAYERSPRITES*2);
return 1;
}
enum spritesopt {
numframes = 0
};
static const char *const sprites_opt[] = {
"numframes",
NULL};
static int sprite_get(lua_State *L)
{
spritedef_t *sprite = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESLIST);
......@@ -382,6 +417,7 @@ int LUA_SkinLib(lua_State *L)
LUA_RegisterUserdataMetatable(L, META_SOUNDSID, soundsid_get, NULL, soundsid_num);
LUA_RegisterUserdataMetatable(L, META_SKINSPRITES, lib_getSkinSprite, NULL, lib_numSkinsSprites);
LUA_RegisterUserdataMetatable(L, META_SKINSPRITESLIST, sprite_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_SKINSPRITESCOMPAT, lib_getSkinSpriteCompat, NULL, lib_numSkinsSpritesCompat); // TODO: 2.3: Delete
skin_fields_ref = Lua_CreateFieldTable(L, skin_opt);
......
......@@ -44,7 +44,7 @@ static int iterationState_gc(lua_State *L)
}
#define push_thinker(th) {\
if ((th)->function.acp1 == (actionf_p1)P_MobjThinker) \
if ((th)->function == (actionf_p1)P_MobjThinker) \
LUA_PushUserdata(L, (th), META_MOBJ); \
else \
lua_pushlightuserdata(L, (th)); \
......@@ -93,7 +93,7 @@ static int lib_iterateThinkers(lua_State *L)
return luaL_error(L, "next thinker invalidated during iteration");
for (; next != &thlist[THINK_MOBJ]; next = next->next)
if (!it->filter || next->function.acp1 == it->filter)
if (!it->filter || next->function == it->filter)
{
push_thinker(next);
if (next->next != &thlist[THINK_MOBJ])
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by LJ Sonic
//
// 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_vectorlib.c
/// \brief vector library for Lua scripting
#include "vector3d.h"
#include "lua_script.h"
#include "lua_libs.h"
// shared by both Vector2D and Vector3D
enum vectorfield_e {
vectorfield_clone = 0,
vectorfield_opposite,
vectorfield_x,
vectorfield_y,
vectorfield_z,
vectorfield_length,
vectorfield_normalized,
};
static const char *const vectorfield_opt[] = {
"vector_clone",
"vector_opposite",
"x",
"y",
"z",
"vector_length",
"vector_normalized",
NULL};
////////////////////////////
// VECTOR2 STATIC MEMBERS //
////////////////////////////
/////////////////////
// VECTOR2 MEMBERS //
/////////////////////
static int vector2d_get(lua_State *L)
{
vector2_t *vec = *((vector2_t **)luaL_checkudata(L, 1, META_VECTOR2));
enum vectorfield_e field = luaL_checkoption(L, 2, vectorfield_opt[0], vectorfield_opt);
switch(field)
{
case vectorfield_x: lua_pushfixed(L, vec->x); return 1;
case vectorfield_y: lua_pushfixed(L, vec->y); return 1;
default: break;
}
return 0;
}
/////////////
// VECTOR3 //
/////////////
static vector3_t *NewVector3(lua_State *L)
{
vector3_t *vec = lua_newuserdata(L, sizeof(*vec));
luaL_getmetatable(L, META_VECTOR3);
lua_setmetatable(L, -2);
return vec;
}
////////////////////////////
// VECTOR3 STATIC MEMBERS //
////////////////////////////
static int vector3d_new(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_optfixed(L, 3, 0);
Vector3D_Set(NewVector3(L), x, y, z);
return 1;
}
static luaL_Reg vector3d[] = {
{"new", vector3d_new},
{NULL, NULL}
};
/////////////////////
// VECTOR3 MEMBERS //
/////////////////////
static int vector3d_clone(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
Vector3D_Copy(NewVector3(L), vec);
return 1;
}
static int vector3d_opposite(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
Vector3D_Opposite(NewVector3(L), vec);
return 1;
}
static int vector3d_get(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
enum vectorfield_e field = luaL_checkoption(L, 2, vectorfield_opt[0], vectorfield_opt);
if (!vec)
return luaL_error(L, "accessed vector3_t doesn't exist anymore.");
switch(field)
{
case vectorfield_clone: lua_pushcfunction(L, vector3d_clone); return 1;
case vectorfield_opposite: lua_pushcfunction(L, vector3d_opposite); return 1;
case vectorfield_x: lua_pushfixed(L, vec->x); return 1;
case vectorfield_y: lua_pushfixed(L, vec->y); return 1;
case vectorfield_z: lua_pushfixed(L, vec->z); return 1;
case vectorfield_length: lua_pushfixed(L, Vector3D_Length(vec)); return 1;
case vectorfield_normalized: Vector3D_Normalize(NewVector3(L), vec); return 1;
default: break;
}
return 0;
}
///////////////////////
// VECTOR3 OPERATORS //
///////////////////////
static int vector3d_eq(lua_State *L)
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
lua_pushboolean(L, Vector3D_Equal(vec1, vec2));
return 1;
}
static int vector3d_op(
lua_State *L,
vector3_t *(*opvector)(vector3_t*, vector3_t*, vector3_t*),
vector3_t *(*opfixed)(vector3_t*, vector3_t*, fixed_t)
)
{
if (lua_isnumber(L, 1) && (opfixed == Vector3D_AddFixed || opfixed == Vector3D_MulFixed))
{
fixed_t n1 = lua_tofixed(L, 1);
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
opfixed(NewVector3(L), vec2, n1);
}
else if (lua_isnumber(L, 2))
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
fixed_t n2 = lua_tofixed(L, 2);
opfixed(NewVector3(L), vec1, n2);
}
else
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
opvector(NewVector3(L), vec1, vec2);
}
return 1;
}
static int vector3d_add(lua_State *L)
{
return vector3d_op(L, Vector3D_Add, Vector3D_AddFixed);
}
static int vector3d_sub(lua_State *L)
{
return vector3d_op(L, Vector3D_Sub, Vector3D_SubFixed);
}
static int vector3d_mul(lua_State *L)
{
return vector3d_op(L, Vector3D_Mul, Vector3D_MulFixed);
}
static int vector3d_div(lua_State *L)
{
return vector3d_op(L, Vector3D_Div, Vector3D_DivFixed);
}
static int vector3d_unm(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
Vector3D_Opposite(NewVector3(L), vec);
return 1;
}
int LUA_VectorLib(lua_State *L)
{
LUA_RegisterUserdataMetatable(L, META_VECTOR2, vector2d_get, NULL, NULL);
luaL_newmetatable(L, META_VECTOR3);
LUA_SetCFunctionField(L, "__index", vector3d_get);
LUA_SetCFunctionField(L, "__eq", vector3d_eq);
LUA_SetCFunctionField(L, "__add", vector3d_add);
LUA_SetCFunctionField(L, "__sub", vector3d_sub);
LUA_SetCFunctionField(L, "__mul", vector3d_mul);
LUA_SetCFunctionField(L, "__div", vector3d_div);
LUA_SetCFunctionField(L, "__unm", vector3d_unm);
lua_pop(L, 1);
luaL_register(L, "Vector3D", vector3d);
return 0;
}
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2025 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -20,8 +20,7 @@
typedef struct aatree_node_s
{
INT32 level;
INT32 key;
void* key;
void* value;
struct aatree_node_s *left, *right;
......@@ -43,8 +42,10 @@ aatree_t *M_AATreeAlloc(UINT32 flags)
static void M_AATreeFree_Node(aatree_node_t *node)
{
if (node->left) M_AATreeFree_Node(node->left);
if (node->right) M_AATreeFree_Node(node->right);
if (node->left)
M_AATreeFree_Node(node->left);
if (node->right)
M_AATreeFree_Node(node->right);
Z_Free(node);
}
......@@ -56,108 +57,132 @@ void M_AATreeFree(aatree_t *aatree)
Z_Free(aatree);
}
static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
static aatree_node_t *M_AATreeRotateRight(aatree_node_t *node)
{
if (node && node->left && node->left->level == node->level)
{
// Not allowed: horizontal left-link. Reverse the
// horizontal link and hook the orphan back in.
aatree_node_t *oldleft = node->left;
node->left = oldleft->right;
oldleft->right = node;
return oldleft;
aatree_node_t *newnode = node->left;
newnode->right = node;
node->left = NULL;
return newnode;
}
// No change needed.
return node;
static aatree_node_t *M_AATreeRotateLeft(aatree_node_t *node)
{
aatree_node_t *newnode = node->right;
newnode->left = node;
node->right = NULL;
return newnode;
}
static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
static aatree_node_t *M_AATreeRebalance(aatree_node_t *node)
{
if (node->right && !node->left)
{
if (node && node->right && node->right->right && node->level == node->right->right->level)
if (node->right->left && !node->right->right)
{
// Not allowed: two consecutive horizontal right-links.
// The middle one becomes the new root at this point,
// with suitable adjustments below.
node->right = M_AATreeRotateRight(node->right);
return M_AATreeRotateLeft(node);
}
aatree_node_t *oldright = node->right;
node->right = oldright->left;
oldright->left = node;
oldright->level++;
if (node->right->right && !node->right->left)
{
return M_AATreeRotateLeft(node);
}
}
else if (node->left && !node->right)
{
if (node->left->right && !node->left->left)
{
node->left = M_AATreeRotateLeft(node->left);
return M_AATreeRotateRight(node);
}
return oldright;
if (node->left->left && !node->left->right)
{
return M_AATreeRotateRight(node);
}
}
// No change needed.
return node;
}
static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, void* key, void* value, aatree_comp_t callback, aatree_dealloc_t deallocator)
{
if (!node)
{
// Nothing here, so just add where we are
node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
node->level = 1;
node->key = key;
if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
else node->value = value;
if (value && (flags & AATREE_ZUSER))
Z_SetUser(value, &node->value);
else
node->value = value;
node->left = node->right = NULL;
}
else
{
if (key < node->key)
node->left = M_AATreeSet_Node(node->left, flags, key, value);
else if (key > node->key)
node->right = M_AATreeSet_Node(node->right, flags, key, value);
if (callback(key, node->key) < 0)
node->left = M_AATreeSet_Node(node->left, flags, key, value, callback, deallocator);
else if (callback(key, node->key) > 0)
node->right = M_AATreeSet_Node(node->right, flags, key, value, callback, deallocator);
else
{
if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
else node->value = value;
if (value && (flags & AATREE_ZUSER))
Z_SetUser(value, &node->value);
else
node->value = value;
if (deallocator)
deallocator(key);
}
node = M_AATreeSkew(node);
node = M_AATreeSplit(node);
node = M_AATreeRebalance(node);
}
return node;
}
void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
void M_AATreeSet(aatree_t *aatree, void* key, void* value, aatree_comp_t callback, aatree_dealloc_t deallocator)
{
aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
I_Assert(callback != NULL);
aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value, callback, deallocator);
}
// Caveat: we don't distinguish between nodes that don't exists
// and nodes with value == NULL.
static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
static void *M_AATreeGet_Node(aatree_node_t *node, void* key, aatree_comp_t callback, aatree_dealloc_t deallocator)
{
if (node)
{
if (node->key == key)
if (callback(key, node->key) == 0)
{
if (deallocator)
deallocator(key);
return node->value;
else if(node->key < key)
return M_AATreeGet_Node(node->right, key);
}
else if(callback(node->key, key) < 0)
return M_AATreeGet_Node(node->right, key, callback, deallocator);
else
return M_AATreeGet_Node(node->left, key);
return M_AATreeGet_Node(node->left, key, callback, deallocator);
}
if (deallocator)
deallocator(key);
return NULL;
}
void *M_AATreeGet(aatree_t *aatree, INT32 key)
void *M_AATreeGet(aatree_t *aatree, void* key, aatree_comp_t callback, aatree_dealloc_t deallocator)
{
return M_AATreeGet_Node(aatree->root, key);
I_Assert(callback != NULL);
return M_AATreeGet_Node(aatree->root, key, callback, deallocator);
}
static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
{
if (node->left) M_AATreeIterate_Node(node->left, callback);
if (node->left)
M_AATreeIterate_Node(node->left, callback);
callback(node->key, node->value);
if (node->right) M_AATreeIterate_Node(node->right, callback);
if (node->right)
M_AATreeIterate_Node(node->right, callback);
}
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2025 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -20,12 +20,14 @@
#define AATREE_ZUSER 1 // Treat values as z_zone-allocated blocks and set their user fields
typedef struct aatree_s aatree_t;
typedef void (*aatree_iter_t)(INT32 key, void *value);
typedef void (*aatree_iter_t)(void* key, void *value);
typedef INT32 (*aatree_comp_t)(void* key, void *value);
typedef void (*aatree_dealloc_t)(void* key);
aatree_t *M_AATreeAlloc(UINT32 flags);
void M_AATreeFree(aatree_t *aatree);
void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
void *M_AATreeGet(aatree_t *aatree, INT32 key);
void M_AATreeSet(aatree_t *aatree, void* key, void* value, aatree_comp_t callback, aatree_dealloc_t deallocator);
void *M_AATreeGet(aatree_t *aatree, void* key, aatree_comp_t callback, aatree_dealloc_t deallocator);
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
#endif
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2013 by "Ninji".
// Copyright (C) 2013-2023 by Sonic Team Junior.
// Copyright (C) 2013-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -75,7 +75,7 @@ static UINT8 cheatf_warp(void)
if (menuactive && currentMenu != &MainDef)
return 0; // Only on the main menu!
S_StartSound(0, sfx_itemup);
S_StartSoundFromEverywhere(sfx_itemup);
// Temporarily unlock stuff.
G_SetUsedCheats(false);
......@@ -97,7 +97,7 @@ static UINT8 cheatf_devmode(void)
if (menuactive && currentMenu != &MainDef)
return 0; // Only on the main menu!
S_StartSound(0, sfx_itemup);
S_StartSoundFromEverywhere(sfx_itemup);
// Just unlock all the things and turn on -debug and console devmode.
G_SetUsedCheats(false);
......@@ -472,7 +472,7 @@ void Command_RTeleport_f(void)
if (!P_SetOrigin(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz))
CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n"));
else
S_StartSound(p->mo, sfx_mixup);
S_StartSoundFromMobj(p->mo, sfx_mixup);
P_MapEnd();
}
......@@ -562,7 +562,7 @@ void Command_Teleport_f(void)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -693,7 +693,7 @@ void Command_Teleport_f(void)
if (!P_SetOrigin(p->mo, intx, inty, intz))
CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n"));
else
S_StartSound(p->mo, sfx_mixup);
S_StartSoundFromMobj(p->mo, sfx_mixup);
P_MapEnd();
}
......@@ -1072,7 +1072,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo = (mobj_t *)th;
......@@ -1110,9 +1110,9 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
mt->pitch = mt->roll = 0;
// Ignore offsets
if (mt->type == MT_EMBLEM)
if (mt->type == mobjinfo[MT_EMBLEM].doomednum)
mt->args[1] = 1;
else
else if (!(mt->type == mobjinfo[MT_METALSONIC_RACE].doomednum || mt->type == mobjinfo[MT_ROSY].doomednum))
mt->args[0] = 1;
return mt;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -155,6 +155,8 @@ void M_ClearSecrets(gamedata_t *data)
data->unlocked[i] = false;
for (i = 0; i < MAXCONDITIONSETS; ++i)
data->achieved[i] = false;
for (i = 0; i < MAXLUACONDITIONS; ++i)
data->lua[i] = false;
data->timesBeaten = data->timesBeatenWithEmeralds = data->timesBeatenUltimate = 0;
......@@ -214,6 +216,8 @@ static UINT8 M_CheckCondition(condition_t *cn, gamedata_t *data)
return data->collected[cn->requirement-1];
case UC_EXTRAEMBLEM: // Requires extra emblem x to be obtained
return data->extraCollected[cn->requirement-1];
case UC_LUA:
return data->lua[cn->requirement-1];
case UC_CONDITIONSET: // requires condition set x to already be achieved
return M_Achieved(cn->requirement-1, data);
}
......@@ -494,6 +498,12 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data)
{
if (dedicated)
{
// See M_MapLocked; don't make dedicated servers annoying.
return false;
}
if (M_MapLocked(mapnum, data) == true)
{
// Warping to locked maps is definitely always a cheat
......
......@@ -47,6 +47,7 @@ typedef enum
UC_EMBLEM, // EMBLEM [emblem number]
UC_EXTRAEMBLEM, // EXTRAEMBLEM [extra emblem number]
UC_CONDITIONSET, // CONDITIONSET [condition set number]
UC_LUA, // LUA [condition set number]
} conditiontype_t;
// Condition Set information
......@@ -141,6 +142,7 @@ typedef struct
#define MAXEMBLEMS 512
#define MAXEXTRAEMBLEMS 48
#define MAXUNLOCKABLES 80
#define MAXLUACONDITIONS 128
/** Time attack information, currently a very small structure.
*/
......@@ -202,6 +204,9 @@ typedef struct
// UNLOCKABLES UNLOCKED
boolean unlocked[MAXUNLOCKABLES];
// LUA DATA (NOT SAVED INTO GAMEDATA)
boolean lua[MAXLUACONDITIONS];
// TIME ATTACK DATA
recorddata_t *mainrecords[NUMMAPS];
nightsdata_t *nightsrecords[NUMMAPS];
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos.
// Copyright (C) 2020-2023 by Lactozilla.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......