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
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • 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-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
  • lua-local
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • map-components-signedness-fixes
  • 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
117 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
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • SRB_release_french_2.2.13
  • accel-momentum
  • acs
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • better-player-states
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • 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-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
  • gitlab-ci
  • 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-debug-library
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • 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
...@@ -98,6 +98,14 @@ void LUA_HUD_AddDrawFill( ...@@ -98,6 +98,14 @@ void LUA_HUD_AddDrawFill(
INT32 h, INT32 h,
INT32 c INT32 c
); );
void LUA_HUD_AddDrawFixedFill(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t w,
fixed_t h,
INT32 c
);
void LUA_HUD_AddDrawString( void LUA_HUD_AddDrawString(
huddrawlist_h list, huddrawlist_h list,
fixed_t x, fixed_t x,
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -88,12 +88,12 @@ static int lib_getSprname(lua_State *L) ...@@ -88,12 +88,12 @@ static int lib_getSprname(lua_State *L)
else if (lua_isstring(L, 1)) else if (lua_isstring(L, 1))
{ {
const char *name = lua_tostring(L, 1); const char *name = lua_tostring(L, 1);
for (i = 0; i < NUMSPRITES; i++) i = R_GetSpriteNumByName(name);
if (fastcmp(name, sprnames[i])) if (i != NUMSPRITES)
{ {
lua_pushinteger(L, i); lua_pushinteger(L, i);
return 1; return 1;
} }
} }
return 0; return 0;
} }
...@@ -242,25 +242,13 @@ static int lib_getSpriteInfo(lua_State *L) ...@@ -242,25 +242,13 @@ static int lib_getSpriteInfo(lua_State *L)
UINT32 i = NUMSPRITES; UINT32 i = NUMSPRITES;
lua_remove(L, 1); lua_remove(L, 1);
if (lua_isstring(L, 1)) if (lua_type(L, 1) == LUA_TSTRING)
{ {
const char *name = lua_tostring(L, 1); const char *name = lua_tostring(L, 1);
INT32 spr; INT32 spr = R_GetSpriteNumByName(name);
for (spr = 0; spr < NUMSPRITES; spr++) if (spr == NUMSPRITES)
{ return luaL_error(L, "unknown sprite name %s", name);
if (fastcmp(name, sprnames[spr])) i = spr;
{
i = spr;
break;
}
}
if (i == NUMSPRITES)
{
char *check;
i = strtol(name, &check, 10);
if (check == name || *check != '\0')
return luaL_error(L, "unknown sprite name %s", name);
}
} }
else else
i = luaL_checkinteger(L, 1); i = luaL_checkinteger(L, 1);
...@@ -359,8 +347,8 @@ static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk) ...@@ -359,8 +347,8 @@ static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk)
default: default:
TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1)); TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1));
} }
if ((idx < 0) || (idx >= 64)) if ((idx < 0) || (idx >= MAXFRAMENUM))
return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, 63); return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, MAXFRAMENUM - 1);
// the values in pivot[] are also tables // the values in pivot[] are also tables
if (PopPivotSubTable(info->pivot, L, stk+2, idx)) if (PopPivotSubTable(info->pivot, L, stk+2, idx))
info->available = true; info->available = true;
...@@ -555,7 +543,7 @@ static int pivotlist_set(lua_State *L) ...@@ -555,7 +543,7 @@ static int pivotlist_set(lua_State *L)
static int pivotlist_num(lua_State *L) static int pivotlist_num(lua_State *L)
{ {
lua_pushinteger(L, 64); lua_pushinteger(L, MAXFRAMENUM);
return 1; return 1;
} }
...@@ -1170,6 +1158,7 @@ enum mobjinfo_e ...@@ -1170,6 +1158,7 @@ enum mobjinfo_e
mobjinfo_activesound, mobjinfo_activesound,
mobjinfo_flags, mobjinfo_flags,
mobjinfo_raisestate, mobjinfo_raisestate,
mobjinfo_name,
}; };
const char *const mobjinfo_opt[] = { const char *const mobjinfo_opt[] = {
...@@ -1197,6 +1186,7 @@ const char *const mobjinfo_opt[] = { ...@@ -1197,6 +1186,7 @@ const char *const mobjinfo_opt[] = {
"activesound", "activesound",
"flags", "flags",
"raisestate", "raisestate",
"name",
NULL, NULL,
}; };
...@@ -1211,6 +1201,8 @@ static int mobjinfo_get(lua_State *L) ...@@ -1211,6 +1201,8 @@ static int mobjinfo_get(lua_State *L)
I_Assert(info != NULL); I_Assert(info != NULL);
I_Assert(info >= mobjinfo); I_Assert(info >= mobjinfo);
mobjtype_t id = info-mobjinfo;
switch (field) switch (field)
{ {
case mobjinfo_doomednum: case mobjinfo_doomednum:
...@@ -1285,6 +1277,21 @@ static int mobjinfo_get(lua_State *L) ...@@ -1285,6 +1277,21 @@ static int mobjinfo_get(lua_State *L)
case mobjinfo_raisestate: case mobjinfo_raisestate:
lua_pushinteger(L, info->raisestate); lua_pushinteger(L, info->raisestate);
break; break;
case mobjinfo_name:
if (id < MT_FIRSTFREESLOT)
{
lua_pushstring(L, MOBJTYPE_LIST[id]+3);
return 1;
}
id -= MT_FIRSTFREESLOT;
if (id < NUMMOBJFREESLOTS && FREE_MOBJS[id])
{
lua_pushstring(L, FREE_MOBJS[id]);
return 1;
}
return 0;
default: default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1)); I_Assert(lua_istable(L, -1));
...@@ -1747,7 +1754,7 @@ static int lib_setSkinColor(lua_State *L) ...@@ -1747,7 +1754,7 @@ static int lib_setSkinColor(lua_State *L)
else if (i == 6 || (str && fastcmp(str,"accessible"))) { else if (i == 6 || (str && fastcmp(str,"accessible"))) {
boolean v = lua_toboolean(L, 3); boolean v = lua_toboolean(L, 3);
if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible) if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible)
CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum); CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.\n", cnum);
else else
info->accessible = v; info->accessible = v;
} }
...@@ -1842,7 +1849,7 @@ static int skincolor_set(lua_State *L) ...@@ -1842,7 +1849,7 @@ static int skincolor_set(lua_State *L)
else if (fastcmp(field,"accessible")) { else if (fastcmp(field,"accessible")) {
boolean v = lua_toboolean(L, 3); boolean v = lua_toboolean(L, 3);
if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible) if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible)
CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum); CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.\n", cnum);
else else
info->accessible = v; info->accessible = v;
} else } else
......
...@@ -10,16 +10,19 @@ ...@@ -10,16 +10,19 @@
/// \brief input library for Lua scripting /// \brief input library for Lua scripting
#include "doomdef.h" #include "doomdef.h"
#include "doomstat.h"
#include "fastcmp.h" #include "fastcmp.h"
#include "g_input.h" #include "g_input.h"
#include "g_game.h" #include "g_game.h"
#include "hu_stuff.h" #include "hu_stuff.h"
#include "i_system.h" #include "i_system.h"
#include "console.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
boolean mousegrabbedbylua = true; boolean mousegrabbedbylua = true;
boolean textinputmodeenabledbylua = false;
boolean ignoregameinputs = false; boolean ignoregameinputs = false;
/////////////// ///////////////
...@@ -129,6 +132,20 @@ static int lib_getCursorPosition(lua_State *L) ...@@ -129,6 +132,20 @@ static int lib_getCursorPosition(lua_State *L)
return 2; return 2;
} }
static int lib_setTextInputMode(lua_State *L)
{
textinputmodeenabledbylua = luaL_checkboolean(L, 1);
if (!(menuactive || CON_Ready() || chat_on))
I_SetTextInputMode(textinputmodeenabledbylua);
return 0;
}
static int lib_getTextInputMode(lua_State *L)
{
lua_pushinteger(L, textinputmodeenabledbylua);
return 1;
}
static luaL_Reg lib[] = { static luaL_Reg lib[] = {
{"gameControlDown", lib_gameControlDown}, {"gameControlDown", lib_gameControlDown},
{"gameControl2Down", lib_gameControl2Down}, {"gameControl2Down", lib_gameControl2Down},
...@@ -143,6 +160,8 @@ static luaL_Reg lib[] = { ...@@ -143,6 +160,8 @@ static luaL_Reg lib[] = {
{"getMouseGrab", lib_getMouseGrab}, {"getMouseGrab", lib_getMouseGrab},
{"setMouseGrab", lib_setMouseGrab}, {"setMouseGrab", lib_setMouseGrab},
{"getCursorPosition", lib_getCursorPosition}, {"getCursorPosition", lib_getCursorPosition},
{"setTextInputMode", lib_setTextInputMode},
{"getTextInputMode", lib_getTextInputMode},
{NULL, NULL} {NULL, NULL}
}; };
...@@ -220,6 +239,28 @@ static int lib_lenGameKeyDown(lua_State *L) ...@@ -220,6 +239,28 @@ static int lib_lenGameKeyDown(lua_State *L)
return 1; return 1;
} }
////////////////
// TEXT EVENT //
////////////////
static int textevent_get(lua_State *L)
{
event_t *event = *((event_t **)luaL_checkudata(L, 1, META_TEXTEVENT));
const char *field = luaL_checkstring(L, 2);
I_Assert(event != NULL);
if (fastcmp(field,"text"))
{
char s[2] = { event->key, 0 };
lua_pushstring(L, s);
}
else
return luaL_error(L, "textevent_t has no field named %s", field);
return 1;
}
/////////////// ///////////////
// KEY EVENT // // KEY EVENT //
/////////////// ///////////////
...@@ -285,6 +326,7 @@ static int mouse_num(lua_State *L) ...@@ -285,6 +326,7 @@ static int mouse_num(lua_State *L)
int LUA_InputLib(lua_State *L) int LUA_InputLib(lua_State *L)
{ {
LUA_RegisterUserdataMetatable(L, META_TEXTEVENT, textevent_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_KEYEVENT, keyevent_get, NULL, NULL); LUA_RegisterUserdataMetatable(L, META_KEYEVENT, keyevent_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_MOUSE, mouse_get, NULL, mouse_num); LUA_RegisterUserdataMetatable(L, META_MOUSE, mouse_get, NULL, mouse_num);
......
// 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 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
extern lua_State *gL; extern lua_State *gL;
extern boolean mousegrabbedbylua; extern boolean mousegrabbedbylua;
extern boolean textinputmodeenabledbylua;
extern boolean ignoregameinputs; extern boolean ignoregameinputs;
#define MUTABLE_TAGS #define MUTABLE_TAGS
...@@ -42,8 +43,11 @@ extern boolean ignoregameinputs; ...@@ -42,8 +43,11 @@ extern boolean ignoregameinputs;
#define META_SKIN "SKIN_T*" #define META_SKIN "SKIN_T*"
#define META_POWERS "PLAYER_T*POWERS" #define META_POWERS "PLAYER_T*POWERS"
#define META_SOUNDSID "SKIN_T*SOUNDSID" #define META_SOUNDSID "SKIN_T*SOUNDSID"
#define META_SKINSPRITES "SKIN_T*SPRITES" #define META_SKINSPRITES "SKIN_T*SKINSPRITES"
#define META_SKINSPRITESLIST "SKIN_T*SPRITES[]" #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_VERTEX "VERTEX_T*"
#define META_LINE "LINE_T*" #define META_LINE "LINE_T*"
...@@ -68,11 +72,15 @@ extern boolean ignoregameinputs; ...@@ -68,11 +72,15 @@ extern boolean ignoregameinputs;
#ifdef MUTABLE_TAGS #ifdef MUTABLE_TAGS
#define META_SECTORTAGLIST "sector_t.taglist" #define META_SECTORTAGLIST "sector_t.taglist"
#endif #endif
#define META_SECTORCUSTOMARGS "SECTOR_T*CUSTOMARGS"
#define META_SIDENUM "LINE_T*SIDENUM" #define META_SIDENUM "LINE_T*SIDENUM"
#define META_LINEARGS "LINE_T*ARGS" #define META_LINEARGS "LINE_T*ARGS"
#define META_LINESTRINGARGS "LINE_T*STRINGARGS" #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_THINGARGS "MAPTHING_T*ARGS"
#define META_THINGSTRINGARGS "MAPTHING_T*STRINGARGS" #define META_THINGSTRINGARGS "MAPTHING_T*STRINGARGS"
#define META_THINGCUSTOMARGS "MAPTHING_T*CUSTOMARGS"
#define META_POLYOBJVERTICES "POLYOBJ_T*VERTICES" #define META_POLYOBJVERTICES "POLYOBJ_T*VERTICES"
#define META_POLYOBJLINES "POLYOBJ_T*LINES" #define META_POLYOBJLINES "POLYOBJ_T*LINES"
#ifdef HAVE_LUA_SEGS #ifdef HAVE_LUA_SEGS
...@@ -92,9 +100,12 @@ extern boolean ignoregameinputs; ...@@ -92,9 +100,12 @@ extern boolean ignoregameinputs;
#define META_LUABANKS "LUABANKS[]*" #define META_LUABANKS "LUABANKS[]*"
#define META_TEXTEVENT "TEXTEVENT_T*"
#define META_KEYEVENT "KEYEVENT_T*" #define META_KEYEVENT "KEYEVENT_T*"
#define META_MOUSE "MOUSE_T*" #define META_MOUSE "MOUSE_T*"
#define META_INTERCEPT "INTERCEPT_T*"
boolean luaL_checkboolean(lua_State *L, int narg); boolean luaL_checkboolean(lua_State *L, int narg);
int LUA_EnumLib(lua_State *L); int LUA_EnumLib(lua_State *L);
...@@ -115,3 +126,4 @@ int LUA_BlockmapLib(lua_State *L); ...@@ -115,3 +126,4 @@ int LUA_BlockmapLib(lua_State *L);
int LUA_HudLib(lua_State *L); int LUA_HudLib(lua_State *L);
int LUA_ColorLib(lua_State *L); int LUA_ColorLib(lua_State *L);
int LUA_InputLib(lua_State *L); int LUA_InputLib(lua_State *L);
int LUA_InterceptLib(lua_State *L);
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -69,6 +69,7 @@ enum sector_e { ...@@ -69,6 +69,7 @@ enum sector_e {
sector_triggerer, sector_triggerer,
sector_friction, sector_friction,
sector_gravity, sector_gravity,
sector_customargs
}; };
static const char *const sector_opt[] = { static const char *const sector_opt[] = {
...@@ -112,6 +113,7 @@ static const char *const sector_opt[] = { ...@@ -112,6 +113,7 @@ static const char *const sector_opt[] = {
"triggerer", "triggerer",
"friction", "friction",
"gravity", "gravity",
"customargs",
NULL}; NULL};
static int sector_fields_ref = LUA_NOREF; static int sector_fields_ref = LUA_NOREF;
...@@ -147,6 +149,7 @@ enum line_e { ...@@ -147,6 +149,7 @@ enum line_e {
line_taglist, line_taglist,
line_args, line_args,
line_stringargs, line_stringargs,
line_customargs,
line_sidenum, line_sidenum,
line_frontside, line_frontside,
line_backside, line_backside,
...@@ -173,6 +176,7 @@ static const char *const line_opt[] = { ...@@ -173,6 +176,7 @@ static const char *const line_opt[] = {
"taglist", "taglist",
"args", "args",
"stringargs", "stringargs",
"customargs",
"sidenum", "sidenum",
"frontside", "frontside",
"backside", "backside",
...@@ -213,7 +217,16 @@ enum side_e { ...@@ -213,7 +217,16 @@ enum side_e {
side_sector, side_sector,
side_special, side_special,
side_repeatcnt, 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[] = { static const char *const side_opt[] = {
...@@ -241,7 +254,16 @@ static const char *const side_opt[] = { ...@@ -241,7 +254,16 @@ static const char *const side_opt[] = {
"sector", "sector",
"special", "special",
"repeatcnt", "repeatcnt",
"light",
"light_top",
"light_mid",
"light_bottom",
"lightabsolute",
"lightabsolute_top",
"lightabsolute_mid",
"lightabsolute_bottom",
"text", "text",
"customargs",
NULL}; NULL};
static int side_fields_ref = LUA_NOREF; static int side_fields_ref = LUA_NOREF;
...@@ -658,6 +680,73 @@ static int sectorlines_num(lua_State *L) ...@@ -658,6 +680,73 @@ static int sectorlines_num(lua_State *L)
return 1; 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 // // sector_t //
////////////// //////////////
...@@ -819,6 +908,9 @@ static int sector_get(lua_State *L) ...@@ -819,6 +908,9 @@ static int sector_get(lua_State *L)
case sector_gravity: // gravity case sector_gravity: // gravity
lua_pushfixed(L, sector->gravity); lua_pushfixed(L, sector->gravity);
return 1; return 1;
case sector_customargs:
LUA_PushUserdata(L, sector->customargs, META_SECTORCUSTOMARGS);
return 1;
} }
return 0; return 0;
} }
...@@ -1114,6 +1206,9 @@ static int line_get(lua_State *L) ...@@ -1114,6 +1206,9 @@ static int line_get(lua_State *L)
case line_stringargs: case line_stringargs:
LUA_PushUserdata(L, line->stringargs, META_LINESTRINGARGS); LUA_PushUserdata(L, line->stringargs, META_LINESTRINGARGS);
return 1; return 1;
case line_customargs:
LUA_PushUserdata(L, line->customargs, META_LINECUSTOMARGS);
return 1;
case line_sidenum: case line_sidenum:
LUA_PushUserdata(L, line->sidenum, META_SIDENUM); LUA_PushUserdata(L, line->sidenum, META_SIDENUM);
return 1; return 1;
...@@ -1311,6 +1406,33 @@ static int side_get(lua_State *L) ...@@ -1311,6 +1406,33 @@ static int side_get(lua_State *L)
case side_repeatcnt: case side_repeatcnt:
lua_pushinteger(L, side->repeatcnt); lua_pushinteger(L, side->repeatcnt);
return 1; 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 // TODO: 2.3: Delete
case side_text: case side_text:
{ {
...@@ -1330,6 +1452,7 @@ static int side_get(lua_State *L) ...@@ -1330,6 +1452,7 @@ static int side_get(lua_State *L)
return 1; return 1;
} }
} }
return 0; return 0;
} }
...@@ -1413,6 +1536,30 @@ static int side_set(lua_State *L) ...@@ -1413,6 +1536,30 @@ static int side_set(lua_State *L)
case side_repeatcnt: case side_repeatcnt:
side->repeatcnt = luaL_checkinteger(L, 3); side->repeatcnt = luaL_checkinteger(L, 3);
break; 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; return 0;
} }
...@@ -2997,9 +3144,12 @@ int LUA_MapLib(lua_State *L) ...@@ -2997,9 +3144,12 @@ int LUA_MapLib(lua_State *L)
LUA_RegisterUserdataMetatable(L, META_SECTORLINES, sectorlines_get, NULL, sectorlines_num); 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_SECTOR, sector_get, sector_set, sector_num);
LUA_RegisterUserdataMetatable(L, META_SUBSECTOR, subsector_get, NULL, subsector_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_LINE, line_get, NULL, line_num);
LUA_RegisterUserdataMetatable(L, META_LINEARGS, lineargs_get, NULL, lineargs_len); LUA_RegisterUserdataMetatable(L, META_LINEARGS, lineargs_get, NULL, lineargs_len);
LUA_RegisterUserdataMetatable(L, META_LINESTRINGARGS, linestringargs_get, NULL, linestringargs_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_SIDENUM, sidenum_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_SIDE, side_get, side_set, side_num); 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_VERTEX, vertex_get, NULL, vertex_num);
...@@ -3009,6 +3159,7 @@ int LUA_MapLib(lua_State *L) ...@@ -3009,6 +3159,7 @@ int LUA_MapLib(lua_State *L)
LUA_RegisterUserdataMetatable(L, META_VECTOR2, vector2_get, NULL, NULL); LUA_RegisterUserdataMetatable(L, META_VECTOR2, vector2_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_VECTOR3, vector3_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_MAPHEADER, mapheaderinfo_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_THINGCUSTOMARGS, thingcustomargs_get, NULL, NULL);
sector_fields_ref = Lua_CreateFieldTable(L, sector_opt); sector_fields_ref = Lua_CreateFieldTable(L, sector_opt);
subsector_fields_ref = Lua_CreateFieldTable(L, subsector_opt); subsector_fields_ref = Lua_CreateFieldTable(L, subsector_opt);
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -69,6 +69,7 @@ enum mobj_e { ...@@ -69,6 +69,7 @@ enum mobj_e {
mobj_color, mobj_color,
mobj_translation, mobj_translation,
mobj_blendmode, mobj_blendmode,
mobj_alpha,
mobj_bnext, mobj_bnext,
mobj_bprev, mobj_bprev,
mobj_hnext, mobj_hnext,
...@@ -150,6 +151,7 @@ static const char *const mobj_opt[] = { ...@@ -150,6 +151,7 @@ static const char *const mobj_opt[] = {
"color", "color",
"translation", "translation",
"blendmode", "blendmode",
"alpha",
"bnext", "bnext",
"bprev", "bprev",
"hnext", "hnext",
...@@ -196,12 +198,12 @@ static int mobj_get(lua_State *L) ...@@ -196,12 +198,12 @@ static int mobj_get(lua_State *L)
enum mobj_e field = Lua_optoption(L, 2, -1, mobj_fields_ref); enum mobj_e field = Lua_optoption(L, 2, -1, mobj_fields_ref);
lua_settop(L, 2); lua_settop(L, 2);
if (!mo || !ISINLEVEL) { if (P_MobjWasRemoved(mo) || !ISINLEVEL) {
if (field == mobj_valid) { if (field == mobj_valid) {
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
return 1; return 1;
} }
if (!mo) { if (P_MobjWasRemoved(mo)) {
return LUA_ErrInvalid(L, "mobj_t"); return LUA_ErrInvalid(L, "mobj_t");
} else } else
return luaL_error(L, "Do not access an mobj_t field outside a level!"); 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) ...@@ -354,6 +356,9 @@ static int mobj_get(lua_State *L)
case mobj_blendmode: case mobj_blendmode:
lua_pushinteger(L, mo->blendmode); lua_pushinteger(L, mo->blendmode);
break; break;
case mobj_alpha:
lua_pushfixed(L, mo->alpha);
break;
case mobj_bnext: case mobj_bnext:
if (mo->blocknode && mo->blocknode->bnext) { if (mo->blocknode && mo->blocknode->bnext) {
LUA_PushUserdata(L, mo->blocknode->bnext->mobj, META_MOBJ); LUA_PushUserdata(L, mo->blocknode->bnext->mobj, META_MOBJ);
...@@ -733,6 +738,16 @@ static int mobj_set(lua_State *L) ...@@ -733,6 +738,16 @@ static int mobj_set(lua_State *L)
mo->blendmode = blendmode; mo->blendmode = blendmode;
break; 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: case mobj_bnext:
return NOSETPOS; return NOSETPOS;
case mobj_bprev: case mobj_bprev:
...@@ -958,6 +973,7 @@ enum mapthing_e { ...@@ -958,6 +973,7 @@ enum mapthing_e {
mapthing_taglist, mapthing_taglist,
mapthing_args, mapthing_args,
mapthing_stringargs, mapthing_stringargs,
mapthing_customargs,
mapthing_mobj, mapthing_mobj,
}; };
...@@ -979,6 +995,7 @@ const char *const mapthing_opt[] = { ...@@ -979,6 +995,7 @@ const char *const mapthing_opt[] = {
"taglist", "taglist",
"args", "args",
"stringargs", "stringargs",
"customargs",
"mobj", "mobj",
NULL, NULL,
}; };
...@@ -1057,6 +1074,9 @@ static int mapthing_get(lua_State *L) ...@@ -1057,6 +1074,9 @@ static int mapthing_get(lua_State *L)
case mapthing_stringargs: case mapthing_stringargs:
LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS); LUA_PushUserdata(L, mt->stringargs, META_THINGSTRINGARGS);
break; break;
case mapthing_customargs:
LUA_PushUserdata(L, mt->customargs, META_THINGCUSTOMARGS);
break;
case mapthing_mobj: case mapthing_mobj:
LUA_PushUserdata(L, mt->mobj, META_MOBJ); LUA_PushUserdata(L, mt->mobj, META_MOBJ);
break; break;
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "r_state.h" #include "r_state.h"
#include "r_sky.h" #include "r_sky.h"
#include "g_game.h" #include "g_game.h"
#include "g_demo.h"
#include "g_input.h" #include "g_input.h"
#include "f_finale.h" #include "f_finale.h"
#include "byteptr.h" #include "byteptr.h"
...@@ -62,6 +63,7 @@ static lua_CFunction liblist[] = { ...@@ -62,6 +63,7 @@ static lua_CFunction liblist[] = {
LUA_HudLib, // HUD stuff LUA_HudLib, // HUD stuff
LUA_ColorLib, // general color functions LUA_ColorLib, // general color functions
LUA_InputLib, // inputs LUA_InputLib, // inputs
LUA_InterceptLib, // intercept_t
NULL NULL
}; };
...@@ -394,6 +396,22 @@ int LUA_PushGlobals(lua_State *L, const char *word) ...@@ -394,6 +396,22 @@ int LUA_PushGlobals(lua_State *L, const char *word)
return 0; return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1; 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")) { } else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds); lua_pushinteger(L, emeralds);
return 1; return 1;
...@@ -412,6 +430,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) ...@@ -412,6 +430,9 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "token")) { } else if (fastcmp(word, "token")) {
lua_pushinteger(L, token); lua_pushinteger(L, token);
return 1; return 1;
} else if (fastcmp(word, "nummaprings")) {
lua_pushinteger(L, nummaprings);
return 1;
} else if (fastcmp(word, "gamestate")) { } else if (fastcmp(word, "gamestate")) {
lua_pushinteger(L, gamestate); lua_pushinteger(L, gamestate);
return 1; return 1;
...@@ -437,6 +458,14 @@ int LUA_PushGlobals(lua_State *L, const char *word) ...@@ -437,6 +458,14 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "chatactive")) { } else if (fastcmp(word, "chatactive")) {
lua_pushboolean(L, chat_on); lua_pushboolean(L, chat_on);
return 1; 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; return 0;
} }
...@@ -460,6 +489,8 @@ int LUA_CheckGlobals(lua_State *L, const char *word) ...@@ -460,6 +489,8 @@ int LUA_CheckGlobals(lua_State *L, const char *word)
emeralds = (UINT16)luaL_checkinteger(L, 2); emeralds = (UINT16)luaL_checkinteger(L, 2);
else if (fastcmp(word, "token")) else if (fastcmp(word, "token"))
token = (UINT32)luaL_checkinteger(L, 2); token = (UINT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "nummaprings"))
nummaprings = (INT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "gravity")) else if (fastcmp(word, "gravity"))
gravity = (fixed_t)luaL_checkinteger(L, 2); gravity = (fixed_t)luaL_checkinteger(L, 2);
else if (fastcmp(word, "stoppedclock")) else if (fastcmp(word, "stoppedclock"))
...@@ -622,9 +653,6 @@ static inline boolean LUA_LoadFile(MYFILE *f, char *name) ...@@ -622,9 +653,6 @@ static inline boolean LUA_LoadFile(MYFILE *f, char *name)
if (!gL) // Lua needs to be initialized if (!gL) // Lua needs to be initialized
LUA_ClearState(); LUA_ClearState();
lua_pushinteger(gL, f->wad);
lua_setfield(gL, LUA_REGISTRYINDEX, "WAD");
lua_pushcfunction(gL, LUA_GetErrorMessage); lua_pushcfunction(gL, LUA_GetErrorMessage);
errorhandlerindex = lua_gettop(gL); errorhandlerindex = lua_gettop(gL);
...@@ -1101,7 +1129,7 @@ static UINT8 GetUserdataArchType(int index) ...@@ -1101,7 +1129,7 @@ static UINT8 GetUserdataArchType(int index)
return ARCH_NULL; return ARCH_NULL;
} }
static UINT8 ArchiveValue(int TABLESINDEX, int myindex) static UINT8 ArchiveValue(save_t *save_p, int TABLESINDEX, int myindex)
{ {
if (myindex < 0) if (myindex < 0)
myindex = lua_gettop(gL)+1+myindex; myindex = lua_gettop(gL)+1+myindex;
...@@ -1109,34 +1137,34 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1109,34 +1137,34 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
case LUA_TNONE: case LUA_TNONE:
case LUA_TNIL: case LUA_TNIL:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
break; break;
// This might be a problem. D: // This might be a problem. D:
case LUA_TLIGHTUSERDATA: case LUA_TLIGHTUSERDATA:
case LUA_TTHREAD: case LUA_TTHREAD:
case LUA_TFUNCTION: case LUA_TFUNCTION:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 2; return 2;
case LUA_TBOOLEAN: case LUA_TBOOLEAN:
WRITEUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE); P_WriteUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE);
break; break;
case LUA_TNUMBER: case LUA_TNUMBER:
{ {
lua_Integer number = lua_tointeger(gL, myindex); lua_Integer number = lua_tointeger(gL, myindex);
if (number >= INT8_MIN && number <= INT8_MAX) if (number >= INT8_MIN && number <= INT8_MAX)
{ {
WRITEUINT8(save_p, ARCH_INT8); P_WriteUINT8(save_p, ARCH_INT8);
WRITESINT8(save_p, number); P_WriteSINT8(save_p, number);
} }
else if (number >= INT16_MIN && number <= INT16_MAX) else if (number >= INT16_MIN && number <= INT16_MAX)
{ {
WRITEUINT8(save_p, ARCH_INT16); P_WriteUINT8(save_p, ARCH_INT16);
WRITEINT16(save_p, number); P_WriteINT16(save_p, number);
} }
else else
{ {
WRITEUINT8(save_p, ARCH_INT32); P_WriteUINT8(save_p, ARCH_INT32);
WRITEFIXED(save_p, number); P_WriteFixed(save_p, number);
} }
break; break;
} }
...@@ -1147,23 +1175,23 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1147,23 +1175,23 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
UINT32 i = 0; UINT32 i = 0;
// if you're wondering why we're writing a string to save_p this way, // 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, // 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'. // so we can't use P_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, // 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 // 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?) // (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 // -- Monster Iestyn 05/08/18
if (len < 255) if (len < 255)
{ {
WRITEUINT8(save_p, ARCH_SMALLSTRING); P_WriteUINT8(save_p, ARCH_SMALLSTRING);
WRITEUINT8(save_p, len); // save size of string P_WriteUINT8(save_p, len); // save size of string
} }
else else
{ {
WRITEUINT8(save_p, ARCH_LARGESTRING); P_WriteUINT8(save_p, ARCH_LARGESTRING);
WRITEUINT32(save_p, len); // save size of string P_WriteUINT32(save_p, len); // save size of string
} }
while (i < len) while (i < len)
WRITECHAR(save_p, s[i++]); // write chars individually, including the embedded zeros P_WriteChar(save_p, s[i++]); // write chars individually, including the embedded zeros
break; break;
} }
case LUA_TTABLE: case LUA_TTABLE:
...@@ -1189,13 +1217,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1189,13 +1217,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
if (t == 0) if (t == 0)
{ {
CONS_Alert(CONS_ERROR, "Too many tables to archive!\n"); CONS_Alert(CONS_ERROR, "Too many tables to archive!\n");
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 0; return 0;
} }
} }
WRITEUINT8(save_p, ARCH_TABLE); P_WriteUINT8(save_p, ARCH_TABLE);
WRITEUINT16(save_p, t); P_WriteUINT16(save_p, t);
if (!found) if (!found)
{ {
...@@ -1211,25 +1239,25 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1211,25 +1239,25 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
case ARCH_MOBJINFO: case ARCH_MOBJINFO:
{ {
mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex)); mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOBJINFO); P_WriteUINT8(save_p, ARCH_MOBJINFO);
WRITEUINT16(save_p, info - mobjinfo); P_WriteUINT16(save_p, info - mobjinfo);
break; break;
} }
case ARCH_STATE: case ARCH_STATE:
{ {
state_t *state = *((state_t **)lua_touserdata(gL, myindex)); state_t *state = *((state_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_STATE); P_WriteUINT8(save_p, ARCH_STATE);
WRITEUINT16(save_p, state - states); P_WriteUINT16(save_p, state - states);
break; break;
} }
case ARCH_MOBJ: case ARCH_MOBJ:
{ {
mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex)); mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex));
if (!mobj) if (!mobj)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MOBJ); P_WriteUINT8(save_p, ARCH_MOBJ);
WRITEUINT32(save_p, mobj->mobjnum); P_WriteUINT32(save_p, mobj->mobjnum);
} }
break; break;
} }
...@@ -1237,10 +1265,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1237,10 +1265,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
player_t *player = *((player_t **)lua_touserdata(gL, myindex)); player_t *player = *((player_t **)lua_touserdata(gL, myindex));
if (!player) if (!player)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_PLAYER); P_WriteUINT8(save_p, ARCH_PLAYER);
WRITEUINT8(save_p, player - players); P_WriteUINT8(save_p, player - players);
} }
break; break;
} }
...@@ -1248,10 +1276,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1248,10 +1276,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex)); mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex));
if (!mapthing) if (!mapthing)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MAPTHING); P_WriteUINT8(save_p, ARCH_MAPTHING);
WRITEUINT16(save_p, mapthing - mapthings); P_WriteUINT16(save_p, mapthing - mapthings);
} }
break; break;
} }
...@@ -1259,10 +1287,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1259,10 +1287,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex)); vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex));
if (!vertex) if (!vertex)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_VERTEX); P_WriteUINT8(save_p, ARCH_VERTEX);
WRITEUINT16(save_p, vertex - vertexes); P_WriteUINT16(save_p, vertex - vertexes);
} }
break; break;
} }
...@@ -1270,10 +1298,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1270,10 +1298,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
line_t *line = *((line_t **)lua_touserdata(gL, myindex)); line_t *line = *((line_t **)lua_touserdata(gL, myindex));
if (!line) if (!line)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_LINE); P_WriteUINT8(save_p, ARCH_LINE);
WRITEUINT16(save_p, line - lines); P_WriteUINT16(save_p, line - lines);
} }
break; break;
} }
...@@ -1281,10 +1309,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1281,10 +1309,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
side_t *side = *((side_t **)lua_touserdata(gL, myindex)); side_t *side = *((side_t **)lua_touserdata(gL, myindex));
if (!side) if (!side)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SIDE); P_WriteUINT8(save_p, ARCH_SIDE);
WRITEUINT16(save_p, side - sides); P_WriteUINT16(save_p, side - sides);
} }
break; break;
} }
...@@ -1292,10 +1320,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1292,10 +1320,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex)); subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex));
if (!subsector) if (!subsector)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SUBSECTOR); P_WriteUINT8(save_p, ARCH_SUBSECTOR);
WRITEUINT16(save_p, subsector - subsectors); P_WriteUINT16(save_p, subsector - subsectors);
} }
break; break;
} }
...@@ -1303,10 +1331,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1303,10 +1331,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex)); sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex));
if (!sector) if (!sector)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SECTOR); P_WriteUINT8(save_p, ARCH_SECTOR);
WRITEUINT16(save_p, sector - sectors); P_WriteUINT16(save_p, sector - sectors);
} }
break; break;
} }
...@@ -1315,10 +1343,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1315,10 +1343,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex)); seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex));
if (!seg) if (!seg)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SEG); P_WriteUINT8(save_p, ARCH_SEG);
WRITEUINT16(save_p, seg - segs); P_WriteUINT16(save_p, seg - segs);
} }
break; break;
} }
...@@ -1326,10 +1354,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1326,10 +1354,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
node_t *node = *((node_t **)lua_touserdata(gL, myindex)); node_t *node = *((node_t **)lua_touserdata(gL, myindex));
if (!node) if (!node)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_NODE); P_WriteUINT8(save_p, ARCH_NODE);
WRITEUINT16(save_p, node - nodes); P_WriteUINT16(save_p, node - nodes);
} }
break; break;
} }
...@@ -1338,16 +1366,16 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1338,16 +1366,16 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex)); ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex));
if (!rover) if (!rover)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
UINT16 i = P_GetFFloorID(rover); UINT16 i = P_GetFFloorID(rover);
if (i == UINT16_MAX) // invalid ID if (i == UINT16_MAX) // invalid ID
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else else
{ {
WRITEUINT8(save_p, ARCH_FFLOOR); P_WriteUINT8(save_p, ARCH_FFLOOR);
WRITEUINT16(save_p, rover->target - sectors); P_WriteUINT16(save_p, rover->target - sectors);
WRITEUINT16(save_p, i); P_WriteUINT16(save_p, i);
} }
} }
break; break;
...@@ -1356,10 +1384,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1356,10 +1384,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex)); polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex));
if (!polyobj) if (!polyobj)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_POLYOBJ); P_WriteUINT8(save_p, ARCH_POLYOBJ);
WRITEUINT16(save_p, polyobj-PolyObjects); P_WriteUINT16(save_p, polyobj-PolyObjects);
} }
break; break;
} }
...@@ -1367,10 +1395,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1367,10 +1395,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex)); pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex));
if (!slope) if (!slope)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SLOPE); P_WriteUINT8(save_p, ARCH_SLOPE);
WRITEUINT16(save_p, slope->id); P_WriteUINT16(save_p, slope->id);
} }
break; break;
} }
...@@ -1378,36 +1406,36 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1378,36 +1406,36 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex)); mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
if (!header) if (!header)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MAPHEADER); P_WriteUINT8(save_p, ARCH_MAPHEADER);
WRITEUINT16(save_p, header - *mapheaderinfo); P_WriteUINT16(save_p, header - *mapheaderinfo);
} }
break; break;
} }
case ARCH_SKINCOLOR: case ARCH_SKINCOLOR:
{ {
skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex)); skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKINCOLOR); P_WriteUINT8(save_p, ARCH_SKINCOLOR);
WRITEUINT16(save_p, info - skincolors); P_WriteUINT16(save_p, info - skincolors);
break; break;
} }
case ARCH_MOUSE: case ARCH_MOUSE:
{ {
mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex)); mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOUSE); P_WriteUINT8(save_p, ARCH_MOUSE);
WRITEUINT8(save_p, m == &mouse ? 1 : 2); P_WriteUINT8(save_p, m == &mouse ? 1 : 2);
break; break;
} }
case ARCH_SKIN: case ARCH_SKIN:
{ {
skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex)); skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKIN); P_WriteUINT8(save_p, ARCH_SKIN);
WRITEUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256 P_WriteUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256
break; break;
} }
default: default:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 2; return 2;
} }
break; break;
...@@ -1415,14 +1443,14 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) ...@@ -1415,14 +1443,14 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
return 0; return 0;
} }
static void ArchiveExtVars(void *pointer, const char *ptype) static void ArchiveExtVars(save_t *save_p, void *pointer, const char *ptype)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i; UINT16 i;
if (!gL) { if (!gL) {
if (fastcmp(ptype,"player")) // players must always be included, even if no vars if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
return; return;
} }
...@@ -1438,7 +1466,7 @@ static void ArchiveExtVars(void *pointer, const char *ptype) ...@@ -1438,7 +1466,7 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
{ // no extra values table { // no extra values table
lua_pop(gL, 1); lua_pop(gL, 1);
if (fastcmp(ptype,"player")) // players must always be included, even if no vars if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
return; return;
} }
...@@ -1450,20 +1478,20 @@ static void ArchiveExtVars(void *pointer, const char *ptype) ...@@ -1450,20 +1478,20 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
if (i == 0) if (i == 0)
{ {
if (fastcmp(ptype,"player")) // always include players even if they have no extra variables if (fastcmp(ptype,"player")) // always include players even if they have no extra variables
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
lua_pop(gL, 1); lua_pop(gL, 1);
return; return;
} }
if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header
WRITEUINT32(save_p, ((mobj_t *)pointer)->mobjnum); P_WriteUINT32(save_p, ((mobj_t *)pointer)->mobjnum);
WRITEUINT16(save_p, i); P_WriteUINT16(save_p, i);
lua_pushnil(gL); lua_pushnil(gL);
while (lua_next(gL, -2)) while (lua_next(gL, -2))
{ {
I_Assert(lua_type(gL, -2) == LUA_TSTRING); I_Assert(lua_type(gL, -2) == LUA_TSTRING);
WRITESTRING(save_p, lua_tostring(gL, -2)); P_WriteString(save_p, lua_tostring(gL, -2));
if (ArchiveValue(TABLESINDEX, -1) == 2) if (ArchiveValue(save_p, 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)); 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);
} }
...@@ -1471,16 +1499,19 @@ static void ArchiveExtVars(void *pointer, const char *ptype) ...@@ -1471,16 +1499,19 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
lua_pop(gL, 1); lua_pop(gL, 1);
} }
// FIXME: remove and pass as local variable
static save_t *lua_save_p;
static int NetArchive(lua_State *L) static int NetArchive(lua_State *L)
{ {
int TABLESINDEX = lua_upvalueindex(1); int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L); int i, n = lua_gettop(L);
for (i = 1; i <= n; i++) for (i = 1; i <= n; i++)
ArchiveValue(TABLESINDEX, i); ArchiveValue(lua_save_p, TABLESINDEX, i);
return n; return n;
} }
static void ArchiveTables(void) static void ArchiveTables(save_t *save_p)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i, n; UINT16 i, n;
...@@ -1499,14 +1530,14 @@ static void ArchiveTables(void) ...@@ -1499,14 +1530,14 @@ static void ArchiveTables(void)
while (lua_next(gL, -2)) while (lua_next(gL, -2))
{ {
// Write key // Write key
e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this. e = ArchiveValue(save_p, TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
if (e == 1) if (e == 1)
n++; // the table contained a new table we'll have to archive. :( 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) 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); 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 // Write value
e = ArchiveValue(TABLESINDEX, -1); e = ArchiveValue(save_p, TABLESINDEX, -1);
if (e == 1) if (e == 1)
n++; // the table contained a new table we'll have to archive. :( n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid value type else if (e == 2) // invalid value type
...@@ -1514,7 +1545,7 @@ static void ArchiveTables(void) ...@@ -1514,7 +1545,7 @@ static void ArchiveTables(void)
lua_pop(gL, 1); lua_pop(gL, 1);
} }
WRITEUINT8(save_p, ARCH_TEND); P_WriteUINT8(save_p, ARCH_TEND);
// Write metatable ID // Write metatable ID
if (lua_getmetatable(gL, -1)) if (lua_getmetatable(gL, -1))
...@@ -1523,19 +1554,19 @@ static void ArchiveTables(void) ...@@ -1523,19 +1554,19 @@ static void ArchiveTables(void)
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_pushvalue(gL, -2); lua_pushvalue(gL, -2);
lua_gettable(gL, -2); lua_gettable(gL, -2);
WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1)); P_WriteUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1));
lua_pop(gL, 3); lua_pop(gL, 3);
} }
else else
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
lua_pop(gL, 1); lua_pop(gL, 1);
} }
} }
static UINT8 UnArchiveValue(int TABLESINDEX) static UINT8 UnArchiveValue(save_t *save_p, int TABLESINDEX)
{ {
UINT8 type = READUINT8(save_p); UINT8 type = P_ReadUINT8(save_p);
switch (type) switch (type)
{ {
case ARCH_NULL: case ARCH_NULL:
...@@ -1548,13 +1579,13 @@ static UINT8 UnArchiveValue(int TABLESINDEX) ...@@ -1548,13 +1579,13 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
lua_pushboolean(gL, false); lua_pushboolean(gL, false);
break; break;
case ARCH_INT8: case ARCH_INT8:
lua_pushinteger(gL, READSINT8(save_p)); lua_pushinteger(gL, P_ReadSINT8(save_p));
break; break;
case ARCH_INT16: case ARCH_INT16:
lua_pushinteger(gL, READINT16(save_p)); lua_pushinteger(gL, P_ReadINT16(save_p));
break; break;
case ARCH_INT32: case ARCH_INT32:
lua_pushinteger(gL, READFIXED(save_p)); lua_pushinteger(gL, P_ReadFixed(save_p));
break; break;
case ARCH_SMALLSTRING: case ARCH_SMALLSTRING:
case ARCH_LARGESTRING: case ARCH_LARGESTRING:
...@@ -1565,23 +1596,23 @@ static UINT8 UnArchiveValue(int TABLESINDEX) ...@@ -1565,23 +1596,23 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
// See my comments in the ArchiveValue function; // See my comments in the ArchiveValue function;
// it's much the same for reading strings as writing them! // it's much the same for reading strings as writing them!
// (i.e. we can't use READSTRING either) // (i.e. we can't use P_ReadString either)
// -- Monster Iestyn 05/08/18 // -- Monster Iestyn 05/08/18
if (type == ARCH_SMALLSTRING) if (type == ARCH_SMALLSTRING)
len = READUINT8(save_p); // length of string, including embedded zeros len = P_ReadUINT8(save_p); // length of string, including embedded zeros
else else
len = READUINT32(save_p); // length of string, including embedded zeros len = P_ReadUINT32(save_p); // length of string, including embedded zeros
value = malloc(len); // make temp buffer of size len value = malloc(len); // make temp buffer of size len
// now read the actual string // now read the actual string
while (i < len) while (i < len)
value[i++] = READCHAR(save_p); // read chars individually, including the embedded zeros value[i++] = P_ReadChar(save_p); // read chars individually, including the embedded zeros
lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros) lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros)
free(value); // free the buffer free(value); // free the buffer
break; break;
} }
case ARCH_TABLE: case ARCH_TABLE:
{ {
UINT16 tid = READUINT16(save_p); UINT16 tid = P_ReadUINT16(save_p);
lua_rawgeti(gL, TABLESINDEX, tid); lua_rawgeti(gL, TABLESINDEX, tid);
if (lua_isnil(gL, -1)) if (lua_isnil(gL, -1))
{ {
...@@ -1594,69 +1625,69 @@ static UINT8 UnArchiveValue(int TABLESINDEX) ...@@ -1594,69 +1625,69 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
break; break;
} }
case ARCH_MOBJINFO: case ARCH_MOBJINFO:
LUA_PushUserdata(gL, &mobjinfo[READUINT16(save_p)], META_MOBJINFO); LUA_PushUserdata(gL, &mobjinfo[P_ReadUINT16(save_p)], META_MOBJINFO);
break; break;
case ARCH_STATE: case ARCH_STATE:
LUA_PushUserdata(gL, &states[READUINT16(save_p)], META_STATE); LUA_PushUserdata(gL, &states[P_ReadUINT16(save_p)], META_STATE);
break; break;
case ARCH_MOBJ: case ARCH_MOBJ:
LUA_PushUserdata(gL, P_FindNewPosition(READUINT32(save_p)), META_MOBJ); LUA_PushUserdata(gL, P_FindNewPosition(P_ReadUINT32(save_p)), META_MOBJ);
break; break;
case ARCH_PLAYER: case ARCH_PLAYER:
LUA_PushUserdata(gL, &players[READUINT8(save_p)], META_PLAYER); LUA_PushUserdata(gL, &players[P_ReadUINT8(save_p)], META_PLAYER);
break; break;
case ARCH_MAPTHING: case ARCH_MAPTHING:
LUA_PushUserdata(gL, &mapthings[READUINT16(save_p)], META_MAPTHING); LUA_PushUserdata(gL, &mapthings[P_ReadUINT16(save_p)], META_MAPTHING);
break; break;
case ARCH_VERTEX: case ARCH_VERTEX:
LUA_PushUserdata(gL, &vertexes[READUINT16(save_p)], META_VERTEX); LUA_PushUserdata(gL, &vertexes[P_ReadUINT16(save_p)], META_VERTEX);
break; break;
case ARCH_LINE: case ARCH_LINE:
LUA_PushUserdata(gL, &lines[READUINT16(save_p)], META_LINE); LUA_PushUserdata(gL, &lines[P_ReadUINT16(save_p)], META_LINE);
break; break;
case ARCH_SIDE: case ARCH_SIDE:
LUA_PushUserdata(gL, &sides[READUINT16(save_p)], META_SIDE); LUA_PushUserdata(gL, &sides[P_ReadUINT16(save_p)], META_SIDE);
break; break;
case ARCH_SUBSECTOR: case ARCH_SUBSECTOR:
LUA_PushUserdata(gL, &subsectors[READUINT16(save_p)], META_SUBSECTOR); LUA_PushUserdata(gL, &subsectors[P_ReadUINT16(save_p)], META_SUBSECTOR);
break; break;
case ARCH_SECTOR: case ARCH_SECTOR:
LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_SECTOR); LUA_PushUserdata(gL, &sectors[P_ReadUINT16(save_p)], META_SECTOR);
break; break;
#ifdef HAVE_LUA_SEGS #ifdef HAVE_LUA_SEGS
case ARCH_SEG: case ARCH_SEG:
LUA_PushUserdata(gL, &segs[READUINT16(save_p)], META_SEG); LUA_PushUserdata(gL, &segs[P_ReadUINT16(save_p)], META_SEG);
break; break;
case ARCH_NODE: case ARCH_NODE:
LUA_PushUserdata(gL, &nodes[READUINT16(save_p)], META_NODE); LUA_PushUserdata(gL, &nodes[P_ReadUINT16(save_p)], META_NODE);
break; break;
#endif #endif
case ARCH_FFLOOR: case ARCH_FFLOOR:
{ {
sector_t *sector = &sectors[READUINT16(save_p)]; sector_t *sector = &sectors[P_ReadUINT16(save_p)];
UINT16 id = READUINT16(save_p); UINT16 id = P_ReadUINT16(save_p);
ffloor_t *rover = P_GetFFloorByID(sector, id); ffloor_t *rover = P_GetFFloorByID(sector, id);
if (rover) if (rover)
LUA_PushUserdata(gL, rover, META_FFLOOR); LUA_PushUserdata(gL, rover, META_FFLOOR);
break; break;
} }
case ARCH_POLYOBJ: case ARCH_POLYOBJ:
LUA_PushUserdata(gL, &PolyObjects[READUINT16(save_p)], META_POLYOBJ); LUA_PushUserdata(gL, &PolyObjects[P_ReadUINT16(save_p)], META_POLYOBJ);
break; break;
case ARCH_SLOPE: case ARCH_SLOPE:
LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE); LUA_PushUserdata(gL, P_SlopeById(P_ReadUINT16(save_p)), META_SLOPE);
break; break;
case ARCH_MAPHEADER: case ARCH_MAPHEADER:
LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER); LUA_PushUserdata(gL, mapheaderinfo[P_ReadUINT16(save_p)], META_MAPHEADER);
break; break;
case ARCH_SKINCOLOR: case ARCH_SKINCOLOR:
LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR); LUA_PushUserdata(gL, &skincolors[P_ReadUINT16(save_p)], META_SKINCOLOR);
break; break;
case ARCH_MOUSE: case ARCH_MOUSE:
LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE); LUA_PushUserdata(gL, P_ReadUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE);
break; break;
case ARCH_SKIN: case ARCH_SKIN:
LUA_PushUserdata(gL, skins[READUINT8(save_p)], META_SKIN); LUA_PushUserdata(gL, skins[P_ReadUINT8(save_p)], META_SKIN);
break; break;
case ARCH_TEND: case ARCH_TEND:
return 1; return 1;
...@@ -1664,10 +1695,10 @@ static UINT8 UnArchiveValue(int TABLESINDEX) ...@@ -1664,10 +1695,10 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
return 0; return 0;
} }
static void UnArchiveExtVars(void *pointer) static void UnArchiveExtVars(save_t *save_p, void *pointer)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 field_count = READUINT16(save_p); UINT16 field_count = P_ReadUINT16(save_p);
UINT16 i; UINT16 i;
char field[1024]; char field[1024];
...@@ -1680,8 +1711,8 @@ static void UnArchiveExtVars(void *pointer) ...@@ -1680,8 +1711,8 @@ static void UnArchiveExtVars(void *pointer)
for (i = 0; i < field_count; i++) for (i = 0; i < field_count; i++)
{ {
READSTRING(save_p, field); P_ReadString(save_p, field);
UnArchiveValue(TABLESINDEX); UnArchiveValue(save_p, TABLESINDEX);
lua_setfield(gL, -2, field); lua_setfield(gL, -2, field);
} }
...@@ -1698,11 +1729,11 @@ static int NetUnArchive(lua_State *L) ...@@ -1698,11 +1729,11 @@ static int NetUnArchive(lua_State *L)
int TABLESINDEX = lua_upvalueindex(1); int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L); int i, n = lua_gettop(L);
for (i = 1; i <= n; i++) for (i = 1; i <= n; i++)
UnArchiveValue(TABLESINDEX); UnArchiveValue(lua_save_p, TABLESINDEX);
return n; return n;
} }
static void UnArchiveTables(void) static void UnArchiveTables(save_t *save_p)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i, n; UINT16 i, n;
...@@ -1719,13 +1750,13 @@ static void UnArchiveTables(void) ...@@ -1719,13 +1750,13 @@ static void UnArchiveTables(void)
lua_rawgeti(gL, TABLESINDEX, i); lua_rawgeti(gL, TABLESINDEX, i);
while (true) while (true)
{ {
UINT8 e = UnArchiveValue(TABLESINDEX); // read key UINT8 e = UnArchiveValue(save_p, TABLESINDEX); // read key
if (e == 1) // End of table if (e == 1) // End of table
break; break;
else if (e == 2) // Key contains a new table else if (e == 2) // Key contains a new table
n++; n++;
if (UnArchiveValue(TABLESINDEX) == 2) // read value if (UnArchiveValue(save_p, TABLESINDEX) == 2) // read value
n++; n++;
if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved) if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved)
...@@ -1737,7 +1768,7 @@ static void UnArchiveTables(void) ...@@ -1737,7 +1768,7 @@ static void UnArchiveTables(void)
lua_rawset(gL, -3); lua_rawset(gL, -3);
} }
metatableid = READUINT16(save_p); metatableid = P_ReadUINT16(save_p);
if (metatableid) if (metatableid)
{ {
// setmetatable(table, registry.metatables[metatableid]) // setmetatable(table, registry.metatables[metatableid])
...@@ -1761,7 +1792,7 @@ void LUA_Step(void) ...@@ -1761,7 +1792,7 @@ void LUA_Step(void)
lua_gc(gL, LUA_GCSTEP, 1); lua_gc(gL, LUA_GCSTEP, 1);
} }
void LUA_Archive(void) void LUA_Archive(save_t *save_p)
{ {
INT32 i; INT32 i;
thinker_t *th; thinker_t *th;
...@@ -1774,29 +1805,30 @@ void LUA_Archive(void) ...@@ -1774,29 +1805,30 @@ void LUA_Archive(void)
if (!playeringame[i] && i > 0) // dedicated servers... if (!playeringame[i] && i > 0) // dedicated servers...
continue; continue;
// all players in game will be archived, even if they just add a 0. // all players in game will be archived, even if they just add a 0.
ArchiveExtVars(&players[i], "player"); ArchiveExtVars(save_p, &players[i], "player");
} }
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) 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; continue;
// archive function will determine when to skip mobjs, // archive function will determine when to skip mobjs,
// and write mobjnum in otherwise. // and write mobjnum in otherwise.
ArchiveExtVars(th, "mobj"); ArchiveExtVars(save_p, th, "mobj");
} }
WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. P_WriteUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
lua_save_p = save_p;
LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode
ArchiveTables(); ArchiveTables(save_p);
if (gL) if (gL)
lua_pop(gL, 1); // pop tables lua_pop(gL, 1); // pop tables
} }
void LUA_UnArchive(void) void LUA_UnArchive(save_t *save_p)
{ {
UINT32 mobjnum; UINT32 mobjnum;
INT32 i; INT32 i;
...@@ -1809,23 +1841,24 @@ void LUA_UnArchive(void) ...@@ -1809,23 +1841,24 @@ void LUA_UnArchive(void)
{ {
if (!playeringame[i] && i > 0) // dedicated servers... if (!playeringame[i] && i > 0) // dedicated servers...
continue; continue;
UnArchiveExtVars(&players[i]); UnArchiveExtVars(save_p, &players[i]);
} }
do { do {
mobjnum = READUINT32(save_p); // read a mobjnum mobjnum = P_ReadUINT32(save_p); // read a mobjnum
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) 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; continue;
if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
continue; continue;
UnArchiveExtVars(th); // apply variables UnArchiveExtVars(save_p, th); // apply variables
} }
} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
lua_save_p = save_p;
LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode
UnArchiveTables(); UnArchiveTables(save_p);
if (gL) if (gL)
lua_pop(gL, 1); // pop tables lua_pop(gL, 1); // pop tables
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#ifndef LUA_SCRIPT_H #ifndef LUA_SCRIPT_H
#define LUA_SCRIPT_H #define LUA_SCRIPT_H
#include "p_saveg.h"
#include "m_fixed.h" #include "m_fixed.h"
#include "doomtype.h" #include "doomtype.h"
#include "d_player.h" #include "d_player.h"
...@@ -52,8 +53,8 @@ void LUA_DumpFile(const char *filename); ...@@ -52,8 +53,8 @@ void LUA_DumpFile(const char *filename);
#endif #endif
fixed_t LUA_EvalMath(const char *word); fixed_t LUA_EvalMath(const char *word);
void LUA_Step(void); void LUA_Step(void);
void LUA_Archive(void); void LUA_Archive(save_t *save_p);
void LUA_UnArchive(void); void LUA_UnArchive(save_t *save_p);
int LUA_PushGlobals(lua_State *L, const char *word); int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_CheckGlobals(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 Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2014-2016 by John "JTE" Muniz. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -54,7 +54,8 @@ enum skin { ...@@ -54,7 +54,8 @@ enum skin {
skin_contspeed, skin_contspeed,
skin_contangle, skin_contangle,
skin_soundsid, skin_soundsid,
skin_sprites, skin_sprites, // TODO: 2.3: Delete
skin_skinsprites,
skin_supersprites, skin_supersprites,
skin_natkcolor skin_natkcolor
}; };
...@@ -95,7 +96,8 @@ static const char *const skin_opt[] = { ...@@ -95,7 +96,8 @@ static const char *const skin_opt[] = {
"contspeed", "contspeed",
"contangle", "contangle",
"soundsid", "soundsid",
"sprites", "sprites", // TODO: 2.3: Delete
"skinsprites",
"supersprites", "supersprites",
"natkcolor", "natkcolor",
NULL}; NULL};
...@@ -219,7 +221,10 @@ static int skin_get(lua_State *L) ...@@ -219,7 +221,10 @@ static int skin_get(lua_State *L)
case skin_soundsid: case skin_soundsid:
LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID); LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID);
break; 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); LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
break; break;
case skin_supersprites: case skin_supersprites:
...@@ -338,15 +343,7 @@ static int soundsid_num(lua_State *L) ...@@ -338,15 +343,7 @@ static int soundsid_num(lua_State *L)
return 1; return 1;
} }
enum spritesopt { // skin.skinsprites[i] -> sprites[i]
numframes = 0
};
static const char *const sprites_opt[] = {
"numframes",
NULL};
// skin.sprites[i] -> sprites[i]
static int lib_getSkinSprite(lua_State *L) static int lib_getSkinSprite(lua_State *L)
{ {
spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES); spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES);
...@@ -359,13 +356,46 @@ static int lib_getSkinSprite(lua_State *L) ...@@ -359,13 +356,46 @@ static int lib_getSkinSprite(lua_State *L)
return 1; return 1;
} }
// #skin.sprites -> NUMPLAYERSPRITES // #skin.skinsprites -> NUMPLAYERSPRITES
static int lib_numSkinsSprites(lua_State *L) static int lib_numSkinsSprites(lua_State *L)
{ {
lua_pushinteger(L, NUMPLAYERSPRITES); lua_pushinteger(L, NUMPLAYERSPRITES);
return 1; 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, "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_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) static int sprite_get(lua_State *L)
{ {
spritedef_t *sprite = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESLIST); spritedef_t *sprite = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESLIST);
...@@ -387,6 +417,7 @@ int LUA_SkinLib(lua_State *L) ...@@ -387,6 +417,7 @@ int LUA_SkinLib(lua_State *L)
LUA_RegisterUserdataMetatable(L, META_SOUNDSID, soundsid_get, NULL, soundsid_num); LUA_RegisterUserdataMetatable(L, META_SOUNDSID, soundsid_get, NULL, soundsid_num);
LUA_RegisterUserdataMetatable(L, META_SKINSPRITES, lib_getSkinSprite, NULL, lib_numSkinsSprites); LUA_RegisterUserdataMetatable(L, META_SKINSPRITES, lib_getSkinSprite, NULL, lib_numSkinsSprites);
LUA_RegisterUserdataMetatable(L, META_SKINSPRITESLIST, sprite_get, NULL, NULL); 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); skin_fields_ref = Lua_CreateFieldTable(L, skin_opt);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2013 by "Ninji". // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -562,7 +562,7 @@ void Command_Teleport_f(void) ...@@ -562,7 +562,7 @@ void Command_Teleport_f(void)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) 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; continue;
mo2 = (mobj_t *)th; mo2 = (mobj_t *)th;
...@@ -1072,7 +1072,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c ...@@ -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) 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; continue;
mo = (mobj_t *)th; mo = (mobj_t *)th;
...@@ -1110,9 +1110,9 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c ...@@ -1110,9 +1110,9 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
mt->pitch = mt->roll = 0; mt->pitch = mt->roll = 0;
// Ignore offsets // Ignore offsets
if (mt->type == MT_EMBLEM) if (mt->type == mobjinfo[MT_EMBLEM].doomednum)
mt->args[1] = 1; mt->args[1] = 1;
else else if (!(mt->type == mobjinfo[MT_METALSONIC_RACE].doomednum || mt->type == mobjinfo[MT_ROSY].doomednum))
mt->args[0] = 1; mt->args[0] = 1;
return mt; return mt;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -475,7 +475,7 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data) ...@@ -475,7 +475,7 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
// that's better than making dedicated server's lives hell. // that's better than making dedicated server's lives hell.
return false; return false;
} }
if (cv_debug || devparm) if (cv_debug || devparm)
return false; // Unlock every level when in devmode. return false; // Unlock every level when in devmode.
...@@ -494,6 +494,12 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data) ...@@ -494,6 +494,12 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
UINT8 M_CampaignWarpIsCheat(INT32 gt, 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) if (M_MapLocked(mapnum, data) == true)
{ {
// Warping to locked maps is definitely always a cheat // Warping to locked maps is definitely always a cheat
......
// SONIC ROBO BLAST 2 // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2 // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// Copyright (C) 2009 by Stephen McGranahan. // Copyright (C) 2009 by Stephen McGranahan.
// //
// This program is free software distributed under the // This program is free software distributed under the
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // 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 // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2025 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "p_setup.h" #include "p_setup.h"
#include "f_finale.h" #include "f_finale.h"
#include "lua_hook.h" #include "lua_hook.h"
#include "lua_libs.h"
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_main.h" #include "hardware/hw_main.h"
...@@ -263,7 +264,7 @@ static void M_ConfirmTeamScramble(INT32 choice); ...@@ -263,7 +264,7 @@ static void M_ConfirmTeamScramble(INT32 choice);
static void M_ConfirmTeamChange(INT32 choice); static void M_ConfirmTeamChange(INT32 choice);
static void M_SecretsMenu(INT32 choice); static void M_SecretsMenu(INT32 choice);
static void M_SetupChoosePlayer(INT32 choice); static void M_SetupChoosePlayer(INT32 choice);
static UINT16 M_SetupChoosePlayerDirect(INT32 choice); static INT32 M_SetupChoosePlayerDirect(INT32 choice);
static void M_QuitSRB2(INT32 choice); static void M_QuitSRB2(INT32 choice);
menu_t SP_MainDef, OP_MainDef; menu_t SP_MainDef, OP_MainDef;
menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef;
...@@ -1071,9 +1072,8 @@ static menuitem_t OP_ChangeControlsMenu[] = ...@@ -1071,9 +1072,8 @@ static menuitem_t OP_ChangeControlsMenu[] =
{IT_CALL | IT_STRING2, NULL, "Move Backward", M_ChangeControl, GC_BACKWARD }, {IT_CALL | IT_STRING2, NULL, "Move Backward", M_ChangeControl, GC_BACKWARD },
{IT_CALL | IT_STRING2, NULL, "Move Left", M_ChangeControl, GC_STRAFELEFT }, {IT_CALL | IT_STRING2, NULL, "Move Left", M_ChangeControl, GC_STRAFELEFT },
{IT_CALL | IT_STRING2, NULL, "Move Right", M_ChangeControl, GC_STRAFERIGHT }, {IT_CALL | IT_STRING2, NULL, "Move Right", M_ChangeControl, GC_STRAFERIGHT },
{IT_CALL | IT_STRING2, NULL, "Jump", M_ChangeControl, GC_JUMP }, {IT_CALL | IT_STRING2, NULL, "Jump", M_ChangeControl, GC_JUMP },
{IT_CALL | IT_STRING2, NULL, "Spin", M_ChangeControl, GC_SPIN }, {IT_CALL | IT_STRING2, NULL, "Spin", M_ChangeControl, GC_SPIN },
{IT_CALL | IT_STRING2, NULL, "Shield Ability", M_ChangeControl, GC_SHIELD },
{IT_HEADER, NULL, "Camera", NULL, 0}, {IT_HEADER, NULL, "Camera", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding {IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Look Up", M_ChangeControl, GC_LOOKUP }, {IT_CALL | IT_STRING2, NULL, "Look Up", M_ChangeControl, GC_LOOKUP },
...@@ -1122,15 +1122,13 @@ static menuitem_t OP_ChangeControlsMenu[] = ...@@ -1122,15 +1122,13 @@ static menuitem_t OP_ChangeControlsMenu[] =
static menuitem_t OP_Joystick1Menu[] = static menuitem_t OP_Joystick1Menu[] =
{ {
{IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup1PJoystickMenu, 0}, {IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup1PJoystickMenu, 10},
{IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis , 30},
{IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis , 20}, {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis , 40},
{IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis , 30}, {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis , 50},
{IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis , 40}, {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis , 60},
{IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis , 50}, {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis , 70},
{IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis , 60}, {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis , 80},
{IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis , 70},
{IT_STRING | IT_CVAR, NULL, "Shield Axis" , &cv_shieldaxis , 80},
{IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis , 90}, {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis , 90},
{IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis ,100}, {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis ,100},
...@@ -1142,15 +1140,13 @@ static menuitem_t OP_Joystick1Menu[] = ...@@ -1142,15 +1140,13 @@ static menuitem_t OP_Joystick1Menu[] =
static menuitem_t OP_Joystick2Menu[] = static menuitem_t OP_Joystick2Menu[] =
{ {
{IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup2PJoystickMenu, 0}, {IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup2PJoystickMenu, 10},
{IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis2 , 30},
{IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis2 , 20}, {IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis2 , 40},
{IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis2 , 30}, {IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis2 , 50},
{IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis2 , 40}, {IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis2 , 60},
{IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis2 , 50}, {IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis2 , 70},
{IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis2 , 60}, {IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis2 , 80},
{IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis2 , 70},
{IT_STRING | IT_CVAR, NULL, "Shield Axis" , &cv_shieldaxis2 , 80},
{IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis2 , 90}, {IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis2 , 90},
{IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis2 ,100}, {IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis2 ,100},
...@@ -2102,6 +2098,12 @@ menu_t OP_PlaystyleDef = { ...@@ -2102,6 +2098,12 @@ menu_t OP_PlaystyleDef = {
0, 0, 0, NULL 0, 0, 0, NULL
}; };
static void M_UpdateItemOn(void)
{
I_SetTextInputMode((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING ||
(currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER);
}
static void M_VideoOptions(INT32 choice) static void M_VideoOptions(INT32 choice)
{ {
(void)choice; (void)choice;
...@@ -2329,6 +2331,7 @@ void Nextmap_OnChange(void) ...@@ -2329,6 +2331,7 @@ void Nextmap_OnChange(void)
{ {
currentMenu->lastOn = itemOn; currentMenu->lastOn = itemOn;
itemOn = nastart; itemOn = nastart;
M_UpdateItemOn();
} }
} }
else if (currentMenu == &SP_TimeAttackDef) else if (currentMenu == &SP_TimeAttackDef)
...@@ -2378,6 +2381,7 @@ void Nextmap_OnChange(void) ...@@ -2378,6 +2381,7 @@ void Nextmap_OnChange(void)
{ {
currentMenu->lastOn = itemOn; currentMenu->lastOn = itemOn;
itemOn = tastart; itemOn = tastart;
M_UpdateItemOn();
} }
if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0') if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0')
...@@ -3128,6 +3132,7 @@ static void M_NextOpt(void) ...@@ -3128,6 +3132,7 @@ static void M_NextOpt(void)
else else
itemOn++; itemOn++;
} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE )); } while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
M_UpdateItemOn();
} }
static void M_PrevOpt(void) static void M_PrevOpt(void)
...@@ -3140,6 +3145,7 @@ static void M_PrevOpt(void) ...@@ -3140,6 +3145,7 @@ static void M_PrevOpt(void)
else else
itemOn--; itemOn--;
} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE )); } while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
M_UpdateItemOn();
} }
// lock out further input in a tic when important buttons are pressed // lock out further input in a tic when important buttons are pressed
...@@ -3306,7 +3312,7 @@ boolean M_Responder(event_t *ev) ...@@ -3306,7 +3312,7 @@ boolean M_Responder(event_t *ev)
if (ch == -1) if (ch == -1)
return false; return false;
else if (ch == gamecontrol[GC_SYSTEMMENU][0] || ch == gamecontrol[GC_SYSTEMMENU][1]) // allow remappable ESC key else if (ev->type != ev_text && (ch == gamecontrol[GC_SYSTEMMENU][0] || ch == gamecontrol[GC_SYSTEMMENU][1])) // allow remappable ESC key
ch = KEY_ESCAPE; ch = KEY_ESCAPE;
// F-Keys // F-Keys
...@@ -3384,9 +3390,16 @@ boolean M_Responder(event_t *ev) ...@@ -3384,9 +3390,16 @@ boolean M_Responder(event_t *ev)
// Handle menuitems which need a specific key handling // Handle menuitems which need a specific key handling
if (routine && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER) if (routine && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER)
{ {
// block text input if ctrl is held, to allow using ctrl+c ctrl+v and ctrl+x
if (ctrldown)
{
routine(ch);
return true;
}
// ignore ev_keydown events if the key maps to a character, since // ignore ev_keydown events if the key maps to a character, since
// the ev_text event will follow immediately after in that case. // the ev_text event will follow immediately after in that case.
if (ev->type == ev_keydown && ch >= 32 && ch <= 127) if (ev->type == ev_keydown && ((ch >= 32 && ch <= 127) || (ch >= KEY_KEYPAD7 && ch <= KEY_KPADDEL)))
return true; return true;
routine(ch); routine(ch);
...@@ -3414,7 +3427,7 @@ boolean M_Responder(event_t *ev) ...@@ -3414,7 +3427,7 @@ boolean M_Responder(event_t *ev)
{ {
// dirty hack: for customising controls, I want only buttons/keys, not moves // dirty hack: for customising controls, I want only buttons/keys, not moves
if (ev->type == ev_mouse || ev->type == ev_mouse2 || ev->type == ev_joystick if (ev->type == ev_mouse || ev->type == ev_mouse2 || ev->type == ev_joystick
|| ev->type == ev_joystick2) || ev->type == ev_joystick2 || ev->type == ev_text)
return true; return true;
if (routine) if (routine)
{ {
...@@ -3651,21 +3664,27 @@ void M_StartControlPanel(void) ...@@ -3651,21 +3664,27 @@ void M_StartControlPanel(void)
currentMenu = &MainDef; currentMenu = &MainDef;
itemOn = singleplr; itemOn = singleplr;
M_UpdateItemOn();
} }
else if (modeattacking) else if (modeattacking)
{ {
currentMenu = &MAPauseDef; currentMenu = &MAPauseDef;
MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
itemOn = mapause_continue; itemOn = mapause_continue;
M_UpdateItemOn();
} }
else if (!(netgame || multiplayer)) // Single Player else if (!(netgame || multiplayer)) // Single Player
{ {
// Devmode unlocks Pandora's Box in the pause menu // Devmode unlocks Pandora's Box and Level Select in the pause menu
boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) || cv_debug || devparm) && !marathonmode); boolean isforbidden = (marathonmode || ultimatemode);
boolean isdebug = ((cv_debug || devparm) && !isforbidden);
if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff. boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !isforbidden) || isdebug);
boolean lselect = ((maplistoption != 0 && !isforbidden) || isdebug);
if (gamestate != GS_LEVEL) // intermission, so gray out stuff.
{ {
SPauseMenu[spause_pandora].status = (pandora) ? (IT_GRAYEDOUT) : (IT_DISABLED); SPauseMenu[spause_pandora].status = (pandora) ? (IT_GRAYEDOUT) : (IT_DISABLED);
SPauseMenu[spause_levelselect].status = (lselect) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
SPauseMenu[spause_retry].status = IT_GRAYEDOUT; SPauseMenu[spause_retry].status = IT_GRAYEDOUT;
} }
else else
...@@ -3675,6 +3694,11 @@ void M_StartControlPanel(void) ...@@ -3675,6 +3694,11 @@ void M_StartControlPanel(void)
++numlives; ++numlives;
SPauseMenu[spause_pandora].status = (pandora) ? (IT_STRING | IT_CALL) : (IT_DISABLED); SPauseMenu[spause_pandora].status = (pandora) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
SPauseMenu[spause_levelselect].status = (lselect) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
if (ultimatemode)
{
SPauseMenu[spause_retry].status = IT_GRAYEDOUT;
}
// The list of things that can disable retrying is (was?) a little too complex // The list of things that can disable retrying is (was?) a little too complex
// for me to want to use the short if statement syntax // for me to want to use the short if statement syntax
...@@ -3684,13 +3708,6 @@ void M_StartControlPanel(void) ...@@ -3684,13 +3708,6 @@ void M_StartControlPanel(void)
SPauseMenu[spause_retry].status = (IT_STRING | IT_CALL); SPauseMenu[spause_retry].status = (IT_STRING | IT_CALL);
} }
// We can always use level select though. :33
// Guarantee it if we have either it unlocked or devmode is enabled
if ((maplistoption != 0 || M_SecretUnlocked(SECRET_LEVELSELECT, serverGamedata) || cv_debug || devparm) && !marathonmode)
SPauseMenu[spause_levelselect].status = (IT_STRING | IT_CALL);
else
SPauseMenu[spause_levelselect].status = (IT_DISABLED);
// And emblem hints. // And emblem hints.
SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED); SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
...@@ -3703,6 +3720,7 @@ void M_StartControlPanel(void) ...@@ -3703,6 +3720,7 @@ void M_StartControlPanel(void)
currentMenu = &SPauseDef; currentMenu = &SPauseDef;
itemOn = spause_continue; itemOn = spause_continue;
M_UpdateItemOn();
} }
else // multiplayer else // multiplayer
{ {
...@@ -3744,6 +3762,7 @@ void M_StartControlPanel(void) ...@@ -3744,6 +3762,7 @@ void M_StartControlPanel(void)
currentMenu = &MPauseDef; currentMenu = &MPauseDef;
itemOn = mpause_continue; itemOn = mpause_continue;
M_UpdateItemOn();
} }
CON_ToggleOff(); // move away console CON_ToggleOff(); // move away console
...@@ -3775,6 +3794,7 @@ void M_ClearMenus(boolean callexitmenufunc) ...@@ -3775,6 +3794,7 @@ void M_ClearMenus(boolean callexitmenufunc)
hidetitlemap = false; hidetitlemap = false;
I_UpdateMouseGrab(); I_UpdateMouseGrab();
I_SetTextInputMode(textinputmodeenabledbylua);
} }
// //
...@@ -3837,6 +3857,7 @@ void M_SetupNextMenu(menu_t *menudef) ...@@ -3837,6 +3857,7 @@ void M_SetupNextMenu(menu_t *menudef)
} }
} }
} }
M_UpdateItemOn();
hidetitlemap = false; hidetitlemap = false;
} }
...@@ -3873,6 +3894,9 @@ void M_Ticker(void) ...@@ -3873,6 +3894,9 @@ void M_Ticker(void)
M_SetupScreenshotMenu(); M_SetupScreenshotMenu();
#if defined (MASTERSERVER) && defined (HAVE_THREADS) #if defined (MASTERSERVER) && defined (HAVE_THREADS)
if (!netgame)
return;
I_lock_mutex(&ms_ServerList_mutex); I_lock_mutex(&ms_ServerList_mutex);
{ {
if (ms_ServerList) if (ms_ServerList)
...@@ -4015,11 +4039,11 @@ static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv) ...@@ -4015,11 +4039,11 @@ static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv)
lumpnum_t leftlump, rightlump, centerlump[2], cursorlump; lumpnum_t leftlump, rightlump, centerlump[2], cursorlump;
patch_t *p; patch_t *p;
leftlump = W_GetNumForName("M_THERML"); leftlump = W_GetNumForPatchName("M_THERML");
rightlump = W_GetNumForName("M_THERMR"); rightlump = W_GetNumForPatchName("M_THERMR");
centerlump[0] = W_GetNumForName("M_THERMM"); centerlump[0] = W_GetNumForPatchName("M_THERMM");
centerlump[1] = W_GetNumForName("M_THERMM"); centerlump[1] = W_GetNumForPatchName("M_THERMM");
cursorlump = W_GetNumForName("M_THERMO"); cursorlump = W_GetNumForPatchName("M_THERMO");
V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_PATCH)); V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_PATCH));
xx += p->width - p->leftoffset; xx += p->width - p->leftoffset;
...@@ -4141,7 +4165,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_ ...@@ -4141,7 +4165,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_
temp = (gametic % temp) * h*2*FRACUNIT; // Which frame to draw temp = (gametic % temp) * h*2*FRACUNIT; // Which frame to draw
V_DrawCroppedPatch(x*FRACUNIT, y*FRACUNIT, (w*FRACUNIT) / 160, (h*FRACUNIT) / 100, flags, patch, NULL, 0, temp, w*2*FRACUNIT, h*2*FRACUNIT); V_DrawCroppedPatch(x*FRACUNIT, y*FRACUNIT, (w*FRACUNIT) / 160, (h*FRACUNIT) / 100, flags, patch, NULL, 0, temp, w*2*FRACUNIT, h*2*FRACUNIT);
W_UnlockCachedPatch(patch); W_UnlockCachedPatch(patch);
return; return;
} }
...@@ -6109,6 +6133,7 @@ void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtyp ...@@ -6109,6 +6133,7 @@ void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtyp
currentMenu = &MessageDef; currentMenu = &MessageDef;
itemOn = 0; itemOn = 0;
M_UpdateItemOn();
} }
static void M_DrawMessageMenu(void) static void M_DrawMessageMenu(void)
...@@ -6183,6 +6208,7 @@ static void M_HandleImageDef(INT32 choice) ...@@ -6183,6 +6208,7 @@ static void M_HandleImageDef(INT32 choice)
if (itemOn >= (INT16)(currentMenu->numitems-1)) if (itemOn >= (INT16)(currentMenu->numitems-1))
itemOn = 0; itemOn = 0;
else itemOn++; else itemOn++;
M_UpdateItemOn();
break; break;
case KEY_LEFTARROW: case KEY_LEFTARROW:
...@@ -6193,6 +6219,7 @@ static void M_HandleImageDef(INT32 choice) ...@@ -6193,6 +6219,7 @@ static void M_HandleImageDef(INT32 choice)
if (!itemOn) if (!itemOn)
itemOn = currentMenu->numitems - 1; itemOn = currentMenu->numitems - 1;
else itemOn--; else itemOn--;
M_UpdateItemOn();
break; break;
case KEY_ESCAPE: case KEY_ESCAPE:
...@@ -6982,7 +7009,10 @@ static void M_LevelSelectWarp(INT32 choice) ...@@ -6982,7 +7009,10 @@ static void M_LevelSelectWarp(INT32 choice)
if (currentMenu == &SP_LevelSelectDef || currentMenu == &SP_PauseLevelSelectDef) if (currentMenu == &SP_LevelSelectDef || currentMenu == &SP_PauseLevelSelectDef)
{ {
if (cursaveslot > 0) // do we have a save slot to load? if (cursaveslot > 0) // do we have a save slot to load?
{
CV_StealthSet(&cv_skin, DEFAULTSKIN); // already handled by loadgame so we don't want this
G_LoadGame((UINT32)cursaveslot, startmap); // reload from SP save data: this is needed to keep score/lives/continues from reverting to defaults G_LoadGame((UINT32)cursaveslot, startmap); // reload from SP save data: this is needed to keep score/lives/continues from reverting to defaults
}
else // no save slot, start new game but keep the current skin else // no save slot, start new game but keep the current skin
{ {
M_ClearMenus(true); M_ClearMenus(true);
...@@ -7389,6 +7419,7 @@ static void M_EmblemHints(INT32 choice) ...@@ -7389,6 +7419,7 @@ static void M_EmblemHints(INT32 choice)
SR_EmblemHintDef.prevMenu = currentMenu; SR_EmblemHintDef.prevMenu = currentMenu;
M_SetupNextMenu(&SR_EmblemHintDef); M_SetupNextMenu(&SR_EmblemHintDef);
itemOn = 2; // always start on back. itemOn = 2; // always start on back.
M_UpdateItemOn();
} }
static void M_DrawEmblemHints(void) static void M_DrawEmblemHints(void)
...@@ -7521,13 +7552,9 @@ static void M_PauseLevelSelect(INT32 choice) ...@@ -7521,13 +7552,9 @@ static void M_PauseLevelSelect(INT32 choice)
SP_PauseLevelSelectDef.prevMenu = currentMenu; SP_PauseLevelSelectDef.prevMenu = currentMenu;
levellistmode = LLM_LEVELSELECT; levellistmode = LLM_LEVELSELECT;
// maplistoption is only specified if not set already // maplistoption is NOT specified, so that this
// and we have the level select unlocked so that it
// transfers the level select list from the menu // transfers the level select list from the menu
// used to enter the game to the pause menu. // used to enter the game to the pause menu.
if (maplistoption == 0 && M_SecretUnlocked(SECRET_LEVELSELECT, serverGamedata))
maplistoption = 1;
if (!M_PrepareLevelPlatter(-1, true)) if (!M_PrepareLevelPlatter(-1, true))
{ {
M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING); M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING);
...@@ -8251,6 +8278,7 @@ static void M_StartTutorial(INT32 choice) ...@@ -8251,6 +8278,7 @@ static void M_StartTutorial(INT32 choice)
gamecomplete = 0; gamecomplete = 0;
cursaveslot = 0; cursaveslot = 0;
maplistoption = 0; maplistoption = 0;
CV_StealthSet(&cv_skin, DEFAULTSKIN); // tutorial accounts for sonic only
G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false); G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false);
} }
...@@ -8350,7 +8378,7 @@ static void M_DrawLoadGameData(void) ...@@ -8350,7 +8378,7 @@ static void M_DrawLoadGameData(void)
if (savegameinfo[savetodraw].lives == -42) if (savegameinfo[savetodraw].lives == -42)
col = 26; col = 26;
else if (savegameinfo[savetodraw].botskin == 3) // & knuckles else if (savegameinfo[savetodraw].botskin == 3) // & knuckles
col = 105; col = 106;
else if (savegameinfo[savetodraw].botskin) // tailsbot or custom else if (savegameinfo[savetodraw].botskin) // tailsbot or custom
col = 134; col = 134;
else else
...@@ -8410,7 +8438,17 @@ static void M_DrawLoadGameData(void) ...@@ -8410,7 +8438,17 @@ static void M_DrawLoadGameData(void)
if (savegameinfo[savetodraw].lives == -42) if (savegameinfo[savetodraw].lives == -42)
V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "NEW GAME"); V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "NEW GAME");
else if (savegameinfo[savetodraw].lives == -666) else if (savegameinfo[savetodraw].lives == -666)
V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "CAN'T LOAD!"); {
if (savegameinfo[savetodraw].continuescore == -62)
{
V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "ADDON NOT LOADED");
V_DrawRightAlignedThinString(x + 79, y-10, V_REDMAP, savegameinfo[savetodraw].skinname);
}
else
{
V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "CAN'T LOAD!");
}
}
else if (savegameinfo[savetodraw].gamemap & 8192) else if (savegameinfo[savetodraw].gamemap & 8192)
V_DrawRightAlignedThinString(x + 79, y, V_GREENMAP, "CLEAR!"); V_DrawRightAlignedThinString(x + 79, y, V_GREENMAP, "CLEAR!");
else else
...@@ -8630,14 +8668,20 @@ static void M_LoadSelect(INT32 choice) ...@@ -8630,14 +8668,20 @@ static void M_LoadSelect(INT32 choice)
M_NewGame(); M_NewGame();
} }
else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed
{
M_LoadGameLevelSelect(0); M_LoadGameLevelSelect(0);
}
else else
{
CV_StealthSet(&cv_skin, DEFAULTSKIN); // already handled by loadgame so we don't want this
G_LoadGame((UINT32)saveSlotSelected, 0); G_LoadGame((UINT32)saveSlotSelected, 0);
}
cursaveslot = saveSlotSelected; cursaveslot = saveSlotSelected;
} }
#define VERSIONSIZE 16 #define VERSIONSIZE 16
#define MISSING { savegameinfo[slot].continuescore = -62; savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; }
#define BADSAVE { savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; } #define BADSAVE { savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; }
#define CHECKPOS if (sav_p >= end_p) BADSAVE #define CHECKPOS if (sav_p >= end_p) BADSAVE
// Reads the save file to list lives, level, player, etc. // Reads the save file to list lives, level, player, etc.
...@@ -8734,10 +8778,11 @@ static void M_ReadSavegameInfo(UINT32 slot) ...@@ -8734,10 +8778,11 @@ static void M_ReadSavegameInfo(UINT32 slot)
CHECKPOS CHECKPOS
READSTRINGN(sav_p, ourSkinName, SKINNAMESIZE); READSTRINGN(sav_p, ourSkinName, SKINNAMESIZE);
savegameinfo[slot].skinnum = R_SkinAvailable(ourSkinName); savegameinfo[slot].skinnum = R_SkinAvailable(ourSkinName);
STRBUFCPY(savegameinfo[slot].skinname, ourSkinName);
if (savegameinfo[slot].skinnum >= numskins if (savegameinfo[slot].skinnum >= numskins
|| !R_SkinUsable(-1, savegameinfo[slot].skinnum)) || !R_SkinUsable(-1, savegameinfo[slot].skinnum))
BADSAVE MISSING
CHECKPOS CHECKPOS
READSTRINGN(sav_p, botSkinName, SKINNAMESIZE); READSTRINGN(sav_p, botSkinName, SKINNAMESIZE);
...@@ -8745,7 +8790,7 @@ static void M_ReadSavegameInfo(UINT32 slot) ...@@ -8745,7 +8790,7 @@ static void M_ReadSavegameInfo(UINT32 slot)
if (savegameinfo[slot].botskin-1 >= numskins if (savegameinfo[slot].botskin-1 >= numskins
|| !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) || !R_SkinUsable(-1, savegameinfo[slot].botskin-1))
BADSAVE MISSING
} }
CHECKPOS CHECKPOS
...@@ -8790,6 +8835,7 @@ static void M_ReadSavegameInfo(UINT32 slot) ...@@ -8790,6 +8835,7 @@ static void M_ReadSavegameInfo(UINT32 slot)
} }
#undef CHECKPOS #undef CHECKPOS
#undef BADSAVE #undef BADSAVE
#undef MISSING
// //
// M_ReadSaveStrings // M_ReadSaveStrings
...@@ -9053,7 +9099,7 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) ...@@ -9053,7 +9099,7 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum)
description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH); description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH);
} }
static UINT16 M_SetupChoosePlayerDirect(INT32 choice) static INT32 M_SetupChoosePlayerDirect(INT32 choice)
{ {
INT32 skinnum, botskinnum; INT32 skinnum, botskinnum;
UINT16 i; UINT16 i;
...@@ -9142,7 +9188,7 @@ static UINT16 M_SetupChoosePlayerDirect(INT32 choice) ...@@ -9142,7 +9188,7 @@ static UINT16 M_SetupChoosePlayerDirect(INT32 choice)
static void M_SetupChoosePlayer(INT32 choice) static void M_SetupChoosePlayer(INT32 choice)
{ {
UINT16 skinset = M_SetupChoosePlayerDirect(choice); INT32 skinset = M_SetupChoosePlayerDirect(choice);
if (skinset != MAXCHARACTERSLOTS) if (skinset != MAXCHARACTERSLOTS)
{ {
M_ChoosePlayer(skinset); M_ChoosePlayer(skinset);
...@@ -9491,6 +9537,8 @@ static void M_ChoosePlayer(INT32 choice) ...@@ -9491,6 +9537,8 @@ static void M_ChoosePlayer(INT32 choice)
//lastmapsaved = 0; //lastmapsaved = 0;
gamecomplete = 0; gamecomplete = 0;
CV_StealthSet(&cv_skin, skins[skinnum]->name);
G_DeferedInitNew(ultmode, G_BuildMapName(startmap), skinnum, false, fromlevelselect); G_DeferedInitNew(ultmode, G_BuildMapName(startmap), skinnum, false, fromlevelselect);
COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this
...@@ -10050,6 +10098,7 @@ static void M_TimeAttack(INT32 choice) ...@@ -10050,6 +10098,7 @@ static void M_TimeAttack(INT32 choice)
Nextmap_OnChange(); Nextmap_OnChange();
itemOn = tastart; // "Start" is selected. itemOn = tastart; // "Start" is selected.
M_UpdateItemOn();
} }
// Drawing function for Nights Attack // Drawing function for Nights Attack
...@@ -10166,7 +10215,7 @@ void M_DrawNightsAttackMenu(void) ...@@ -10166,7 +10215,7 @@ void M_DrawNightsAttackMenu(void)
skinnumber = 0; //Default to Sonic skinnumber = 0; //Default to Sonic
else else
skinnumber = (cv_chooseskin.value-1); skinnumber = (cv_chooseskin.value-1);
spritedef_t *sprdef = &skins[skinnumber]->sprites[SPR2_NFLY]; //Make our patch the selected character's NFLY sprite spritedef_t *sprdef = &skins[skinnumber]->sprites[SPR2_NFLY]; //Make our patch the selected character's NFLY sprite
spritetimer = FixedInt(ntsatkdrawtimer/2) % skins[skinnumber]->sprites[SPR2_NFLY].numframes; //Make the sprite timer cycle though all the frames at 2 tics per frame spritetimer = FixedInt(ntsatkdrawtimer/2) % skins[skinnumber]->sprites[SPR2_NFLY].numframes; //Make the sprite timer cycle though all the frames at 2 tics per frame
spriteframe_t *sprframe = &sprdef->spriteframes[spritetimer]; //Our animation frame is equal to the number on the timer spriteframe_t *sprframe = &sprdef->spriteframes[spritetimer]; //Our animation frame is equal to the number on the timer
...@@ -10179,11 +10228,14 @@ void M_DrawNightsAttackMenu(void) ...@@ -10179,11 +10228,14 @@ void M_DrawNightsAttackMenu(void)
color = skins[skinnumber]->supercolor+4; color = skins[skinnumber]->supercolor+4;
else //If you don't go super in NiGHTS or at all, use prefcolor else //If you don't go super in NiGHTS or at all, use prefcolor
color = skins[skinnumber]->prefcolor; color = skins[skinnumber]->prefcolor;
angle_t fa = (FixedAngle(((FixedInt(ntsatkdrawtimer * 4)) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK; angle_t fa = (FixedAngle(((FixedInt(ntsatkdrawtimer * 4)) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK;
fixed_t scale = skins[skinnumber]->highresscale;
if (skins[skinnumber]->shieldscale)
scale = FixedDiv(scale, skins[skinnumber]->shieldscale);
V_DrawFixedPatch(270<<FRACBITS, (186<<FRACBITS) - 8*FINESINE(fa), V_DrawFixedPatch(270<<FRACBITS, (186<<FRACBITS) - 8*FINESINE(fa),
FixedDiv(skins[skinnumber]->highresscale, skins[skinnumber]->shieldscale), scale,
(sprframe->flip & 1<<6) ? V_FLIP : 0, (sprframe->flip & 1<<6) ? V_FLIP : 0,
natksprite, natksprite,
R_GetTranslationColormap(TC_BLINK, color, GTC_CACHE)); R_GetTranslationColormap(TC_BLINK, color, GTC_CACHE));
...@@ -10288,6 +10340,7 @@ static void M_NightsAttack(INT32 choice) ...@@ -10288,6 +10340,7 @@ static void M_NightsAttack(INT32 choice)
Nextmap_OnChange(); Nextmap_OnChange();
itemOn = nastart; // "Start" is selected. itemOn = nastart; // "Start" is selected.
M_UpdateItemOn();
} }
// Player has selected the "START" from the nights attack screen // Player has selected the "START" from the nights attack screen
...@@ -10607,6 +10660,7 @@ static void M_ModeAttackEndGame(INT32 choice) ...@@ -10607,6 +10660,7 @@ static void M_ModeAttackEndGame(INT32 choice)
break; break;
} }
itemOn = currentMenu->lastOn; itemOn = currentMenu->lastOn;
M_UpdateItemOn();
G_SetGamestate(GS_TIMEATTACK); G_SetGamestate(GS_TIMEATTACK);
modeattacking = ATTACKING_NONE; modeattacking = ATTACKING_NONE;
M_ChangeMenuMusic("_title", true); M_ChangeMenuMusic("_title", true);
...@@ -10688,6 +10742,7 @@ static void M_Marathon(INT32 choice) ...@@ -10688,6 +10742,7 @@ static void M_Marathon(INT32 choice)
titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
M_SetupNextMenu(&SP_MarathonDef); M_SetupNextMenu(&SP_MarathonDef);
itemOn = marathonstart; // "Start" is selected. itemOn = marathonstart; // "Start" is selected.
M_UpdateItemOn();
recatkdrawtimer = (50-8) * FRACUNIT; recatkdrawtimer = (50-8) * FRACUNIT;
char_scroll = 0; char_scroll = 0;
} }
...@@ -11078,7 +11133,7 @@ static void M_Refresh(INT32 choice) ...@@ -11078,7 +11133,7 @@ static void M_Refresh(INT32 choice)
// note: this is the one case where 0 is a valid room number // note: this is the one case where 0 is a valid room number
// because it corresponds to "All" // because it corresponds to "All"
CL_UpdateServerList(!(ms_RoomId < 0), ms_RoomId); CL_UpdateServerList(cv_masterserver_room_id.value >= 0, cv_masterserver_room_id.value);
// first page of servers // first page of servers
serverlistpage = 0; serverlistpage = 0;
...@@ -11088,37 +11143,11 @@ static INT32 menuRoomIndex = 0; ...@@ -11088,37 +11143,11 @@ static INT32 menuRoomIndex = 0;
static void M_DrawRoomMenu(void) static void M_DrawRoomMenu(void)
{ {
static fixed_t frame = -(12 << FRACBITS);
int dot_frame;
char text[4];
const char *rmotd; const char *rmotd;
const char *waiting_message; const char *waiting_message;
int dots;
if (m_waiting_mode) if (m_waiting_mode)
{ currentMenu->menuitems[0].text = "...";
dot_frame = (int)(frame >> FRACBITS) / 4;
dots = dot_frame + 3;
strcpy(text, " ");
if (dots > 0)
{
if (dot_frame < 0)
dot_frame = 0;
if (dot_frame != 3)
strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame));
}
frame += renderdeltatics;
while (frame >= (12 << FRACBITS))
frame -= 12 << FRACBITS;
currentMenu->menuitems[0].text = text;
}
// use generic drawer for cursor, items and title // use generic drawer for cursor, items and title
M_DrawGenericMenu(); M_DrawGenericMenu();
...@@ -11164,7 +11193,7 @@ static void M_DrawConnectMenu(void) ...@@ -11164,7 +11193,7 @@ static void M_DrawConnectMenu(void)
numPages = 1; numPages = 1;
// Room name // Room name
if (ms_RoomId < 0) if (cv_masterserver_room_id.value < 0)
V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_room].alphaKey, V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_room].alphaKey,
V_YELLOWMAP, (itemOn == mp_connect_room) ? "<Select to change>" : "<Unlisted Mode>"); V_YELLOWMAP, (itemOn == mp_connect_room) ? "<Select to change>" : "<Unlisted Mode>");
else else
...@@ -11392,7 +11421,7 @@ static void M_ConnectMenu(INT32 choice) ...@@ -11392,7 +11421,7 @@ static void M_ConnectMenu(INT32 choice)
// first page of servers // first page of servers
serverlistpage = 0; serverlistpage = 0;
if (ms_RoomId < 0) if (cv_masterserver_room_id.value < 0)
{ {
M_RoomMenu(0); // Select a room instead of staring at an empty list M_RoomMenu(0); // Select a room instead of staring at an empty list
// This prevents us from returning to the modified game alert. // This prevents us from returning to the modified game alert.
...@@ -11401,6 +11430,7 @@ static void M_ConnectMenu(INT32 choice) ...@@ -11401,6 +11430,7 @@ static void M_ConnectMenu(INT32 choice)
else else
M_SetupNextMenu(&MP_ConnectDef); M_SetupNextMenu(&MP_ConnectDef);
itemOn = 0; itemOn = 0;
M_UpdateItemOn();
M_Refresh(0); M_Refresh(0);
} }
...@@ -11487,10 +11517,10 @@ static void M_ChooseRoom(INT32 choice) ...@@ -11487,10 +11517,10 @@ static void M_ChooseRoom(INT32 choice)
#endif #endif
if (choice == 0) if (choice == 0)
ms_RoomId = -1; CV_SetValue(&cv_masterserver_room_id, -1);
else else
{ {
ms_RoomId = roomIds[choice-1]; CV_SetValue(&cv_masterserver_room_id, roomIds[choice-1]);
menuRoomIndex = choice - 1; menuRoomIndex = choice - 1;
} }
...@@ -11559,7 +11589,7 @@ static void M_DrawServerMenu(void) ...@@ -11559,7 +11589,7 @@ static void M_DrawServerMenu(void)
if (currentMenu == &MP_ServerDef) if (currentMenu == &MP_ServerDef)
{ {
M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight/2, "Server settings", true, false); M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight/2, "Server settings", true, false);
if (ms_RoomId < 0) if (cv_masterserver_room_id.value < 0)
V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey,
V_YELLOWMAP, (itemOn == mp_server_room) ? "<Select to change>" : "<Unlisted Mode>"); V_YELLOWMAP, (itemOn == mp_server_room) ? "<Select to change>" : "<Unlisted Mode>");
else else
...@@ -11655,11 +11685,12 @@ static void M_ServerOptions(INT32 choice) ...@@ -11655,11 +11685,12 @@ static void M_ServerOptions(INT32 choice)
static void M_StartServerMenu(INT32 choice) static void M_StartServerMenu(INT32 choice)
{ {
(void)choice; (void)choice;
ms_RoomId = -1; CV_SetValue(&cv_masterserver_room_id, -1);
levellistmode = LLM_CREATESERVER; levellistmode = LLM_CREATESERVER;
Newgametype_OnChange(); Newgametype_OnChange();
M_SetupNextMenu(&MP_ServerDef); M_SetupNextMenu(&MP_ServerDef);
itemOn = 1; itemOn = 1;
M_UpdateItemOn();
} }
// ============== // ==============
...@@ -11826,8 +11857,7 @@ static void M_HandleConnectIP(INT32 choice) ...@@ -11826,8 +11857,7 @@ static void M_HandleConnectIP(INT32 choice)
if ( ctrldown ) { if ( ctrldown ) {
switch (choice) { switch (choice) {
case 'v': case 'v': // ctrl+v, pasting
case 'V': // ctrl+v, pasting
{ {
const char *paste = I_ClipboardPaste(); const char *paste = I_ClipboardPaste();
...@@ -11840,17 +11870,21 @@ static void M_HandleConnectIP(INT32 choice) ...@@ -11840,17 +11870,21 @@ static void M_HandleConnectIP(INT32 choice)
break; break;
} }
case KEY_INS: case KEY_INS:
case 'c': case 'c': // ctrl+c, ctrl+insert, copying
case 'C': // ctrl+c, ctrl+insert, copying if (l != 0) // Don't replace the clipboard without any text
I_ClipboardCopy(setupm_ip, l); {
S_StartSound(NULL,sfx_menu1); // Tails I_ClipboardCopy(setupm_ip, l);
S_StartSound(NULL,sfx_menu1); // Tails
}
break; break;
case 'x': case 'x': // ctrl+x, cutting
case 'X': // ctrl+x, cutting if (l != 0) // Don't replace the clipboard without any text
I_ClipboardCopy(setupm_ip, l); {
S_StartSound(NULL,sfx_menu1); // Tails I_ClipboardCopy(setupm_ip, l);
setupm_ip[0] = 0; S_StartSound(NULL,sfx_menu1); // Tails
setupm_ip[0] = 0;
}
break; break;
default: // otherwise do nothing default: // otherwise do nothing
...@@ -11874,9 +11908,12 @@ static void M_HandleConnectIP(INT32 choice) ...@@ -11874,9 +11908,12 @@ static void M_HandleConnectIP(INT32 choice)
break; break;
} }
case KEY_DEL: // shift+delete, cutting case KEY_DEL: // shift+delete, cutting
I_ClipboardCopy(setupm_ip, l); if (l != 0) // Don't replace the clipboard without any text
S_StartSound(NULL,sfx_menu1); // Tails {
setupm_ip[0] = 0; I_ClipboardCopy(setupm_ip, l);
S_StartSound(NULL,sfx_menu1); // Tails
setupm_ip[0] = 0;
}
break; break;
default: // otherwise do nothing. default: // otherwise do nothing.
break; break;
...@@ -11897,15 +11934,6 @@ static void M_HandleConnectIP(INT32 choice) ...@@ -11897,15 +11934,6 @@ static void M_HandleConnectIP(INT32 choice)
setupm_ip[l] = (char)choice; setupm_ip[l] = (char)choice;
setupm_ip[l+1] = 0; setupm_ip[l+1] = 0;
} }
else if (choice >= 199 && choice <= 211 && choice != 202 && choice != 206) //numpad too!
{
char keypad_translation[] = {'7','8','9','-','4','5','6','+','1','2','3','0','.'};
choice = keypad_translation[choice - 199];
S_StartSound(NULL,sfx_menu1); // Tails
setupm_ip[l] = (char)choice;
setupm_ip[l+1] = 0;
}
break; break;
} }
...@@ -12256,7 +12284,9 @@ static void M_DrawSetupMultiPlayerMenu(void) ...@@ -12256,7 +12284,9 @@ static void M_DrawSetupMultiPlayerMenu(void)
if (multi_frame >= sprdef->numframes) if (multi_frame >= sprdef->numframes)
multi_frame = 0; multi_frame = 0;
scale = FixedDiv(skins[setupm_fakeskin]->highresscale, skins[setupm_fakeskin]->shieldscale); scale = skins[setupm_fakeskin]->highresscale;
if (skins[setupm_fakeskin]->shieldscale)
scale = FixedDiv(scale, skins[setupm_fakeskin]->shieldscale);
#define chary (y+64) #define chary (y+64)
...@@ -12289,7 +12319,7 @@ static void M_DrawSetupMultiPlayerMenu(void) ...@@ -12289,7 +12319,7 @@ static void M_DrawSetupMultiPlayerMenu(void)
V_DrawFixedPatch( V_DrawFixedPatch(
x<<FRACBITS, x<<FRACBITS,
chary<<FRACBITS, chary<<FRACBITS,
FixedDiv(skins[setupm_fakeskin]->highresscale, skins[setupm_fakeskin]->shieldscale), scale,
flags, patch, colormap); flags, patch, colormap);
goto colordraw; goto colordraw;
...@@ -13071,7 +13101,10 @@ static void M_SetupScreenshotMenu(void) ...@@ -13071,7 +13101,10 @@ static void M_SetupScreenshotMenu(void)
{ {
item->status = IT_GRAYEDOUT; item->status = IT_GRAYEDOUT;
if ((currentMenu == &OP_ScreenshotOptionsDef) && (itemOn == op_screenshot_colorprofile)) // Can't select that if ((currentMenu == &OP_ScreenshotOptionsDef) && (itemOn == op_screenshot_colorprofile)) // Can't select that
{
itemOn = op_screenshot_storagelocation; itemOn = op_screenshot_storagelocation;
M_UpdateItemOn();
}
} }
else else
#endif #endif
...@@ -13269,23 +13302,23 @@ static void M_Setup1PControlsMenu(INT32 choice) ...@@ -13269,23 +13302,23 @@ static void M_Setup1PControlsMenu(INT32 choice)
currentMenu->lastOn = itemOn; currentMenu->lastOn = itemOn;
// Unhide the nine non-P2 controls and their headers // Unhide the nine non-P2 controls and their headers
//OP_ChangeControlsMenu[19+0].status = IT_HEADER; //OP_ChangeControlsMenu[18+0].status = IT_HEADER;
//OP_ChangeControlsMenu[19+1].status = IT_SPACE; //OP_ChangeControlsMenu[18+1].status = IT_SPACE;
// ... // ...
OP_ChangeControlsMenu[19+2].status = IT_CALL|IT_STRING2; OP_ChangeControlsMenu[18+2].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+3].status = IT_CALL|IT_STRING2; OP_ChangeControlsMenu[18+3].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+4].status = IT_CALL|IT_STRING2; OP_ChangeControlsMenu[18+4].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+5].status = IT_CALL|IT_STRING2; OP_ChangeControlsMenu[18+5].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+6].status = IT_CALL|IT_STRING2; OP_ChangeControlsMenu[18+6].status = IT_CALL|IT_STRING2;
//OP_ChangeControlsMenu[19+7].status = IT_CALL|IT_STRING2; //OP_ChangeControlsMenu[18+7].status = IT_CALL|IT_STRING2;
//OP_ChangeControlsMenu[19+8].status = IT_CALL|IT_STRING2; //OP_ChangeControlsMenu[18+8].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+9].status = IT_CALL|IT_STRING2; OP_ChangeControlsMenu[18+9].status = IT_CALL|IT_STRING2;
// ... // ...
OP_ChangeControlsMenu[29+0].status = IT_HEADER; OP_ChangeControlsMenu[28+0].status = IT_HEADER;
OP_ChangeControlsMenu[29+1].status = IT_SPACE; OP_ChangeControlsMenu[28+1].status = IT_SPACE;
// ... // ...
OP_ChangeControlsMenu[29+2].status = IT_CALL|IT_STRING2; OP_ChangeControlsMenu[28+2].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[29+3].status = IT_CALL|IT_STRING2; OP_ChangeControlsMenu[28+3].status = IT_CALL|IT_STRING2;
OP_ChangeControlsDef.prevMenu = &OP_P1ControlsDef; OP_ChangeControlsDef.prevMenu = &OP_P1ControlsDef;
OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level
...@@ -13301,23 +13334,23 @@ static void M_Setup2PControlsMenu(INT32 choice) ...@@ -13301,23 +13334,23 @@ static void M_Setup2PControlsMenu(INT32 choice)
currentMenu->lastOn = itemOn; currentMenu->lastOn = itemOn;
// Hide the nine non-P2 controls and their headers // Hide the nine non-P2 controls and their headers
//OP_ChangeControlsMenu[19+0].status = IT_GRAYEDOUT2; //OP_ChangeControlsMenu[18+0].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[19+1].status = IT_GRAYEDOUT2; //OP_ChangeControlsMenu[18+1].status = IT_GRAYEDOUT2;
// ... // ...
OP_ChangeControlsMenu[19+2].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[18+2].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+3].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[18+3].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+4].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[18+4].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+5].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[18+5].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+6].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[18+6].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[19+7].status = IT_GRAYEDOUT2; //OP_ChangeControlsMenu[18+7].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[19+8].status = IT_GRAYEDOUT2; //OP_ChangeControlsMenu[18+8].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+9].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[18+9].status = IT_GRAYEDOUT2;
// ... // ...
OP_ChangeControlsMenu[29+0].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[28+0].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[29+1].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[28+1].status = IT_GRAYEDOUT2;
// ... // ...
OP_ChangeControlsMenu[29+2].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[28+2].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[29+3].status = IT_GRAYEDOUT2; OP_ChangeControlsMenu[28+3].status = IT_GRAYEDOUT2;
OP_ChangeControlsDef.prevMenu = &OP_P2ControlsDef; OP_ChangeControlsDef.prevMenu = &OP_P2ControlsDef;
OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level
...@@ -14118,6 +14151,33 @@ static INT32 quitsounds[] = ...@@ -14118,6 +14151,33 @@ static INT32 quitsounds[] =
sfx_chchng // Tails 11-09-99 sfx_chchng // Tails 11-09-99
}; };
const char *QuitScreenMessages[3] = {
(
"Design and content in\n"
"SRB2 is copyright\n"
"1998-2025 by STJr. All\n"
"original material in\n"
"this game is copyrighted\n"
"by their respective\n"
"owners, and no copyright\n"
"infringement is\n"
"intended. STJr's staff\n"
"make no profit\n"
"whatsoever (in\n"
"fact, we lose\n"
"money)."
),
(
"THIS GAME SHOULD NOT BE SOLD!"
),
(
"STJr is in no way affiliated\n"
"with SEGA or Sonic Team."
)
};
void M_QuitResponse(INT32 ch) void M_QuitResponse(INT32 ch)
{ {
tic_t ptime; tic_t ptime;
...@@ -14139,6 +14199,9 @@ void M_QuitResponse(INT32 ch) ...@@ -14139,6 +14199,9 @@ void M_QuitResponse(INT32 ch)
while (ptime > I_GetTime()) while (ptime > I_GetTime())
{ {
V_DrawScaledPatch(0, 0, 0, W_CachePatchName("GAMEQUIT", PU_PATCH)); // Demo 3 Quit Screen Tails 06-16-2001 V_DrawScaledPatch(0, 0, 0, W_CachePatchName("GAMEQUIT", PU_PATCH)); // Demo 3 Quit Screen Tails 06-16-2001
V_DrawCenteredString(2+(V_StringWidth(QuitScreenMessages[0], V_ALLOWLOWERCASE)/2), 4, V_ALLOWLOWERCASE, QuitScreenMessages[0]);
V_DrawCenteredString(160, 166, V_ALLOWLOWERCASE|V_REDMAP, QuitScreenMessages[1]);
V_DrawCenteredString(160, 176, V_ALLOWLOWERCASE, QuitScreenMessages[2]);
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001 I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
I_Sleep(cv_sleep.value); I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value); I_UpdateTime(cv_timescale.value);
......