Skip to content
Snippets Groups Projects

Compare revisions

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

Source

Select target project
No results found
Select Git revision
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2214-pre4
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • acs
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • better-distance-math
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • 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
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.15
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
142 results

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
  • voltybystorm/SRB2
  • ZenithNeko/srb-2-xp
  • Nep2Disk/SRB2
  • Cloudeon/SRB2
  • mushe/srb-2-ps-b
122 results
Select Git revision
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • PS3
  • 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
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -226,6 +226,7 @@ enum player_e
player_quittime,
player_lastinputtime,
player_ping,
player_muted,
player_fovadd
};
......@@ -374,6 +375,7 @@ static const char *const player_opt[] = {
"quittime",
"lastinputtime",
"ping",
"muted",
"fovadd",
NULL,
};
......@@ -835,6 +837,9 @@ static int player_get(lua_State *L)
case player_ping:
lua_pushinteger(L, playerpingtable[plr - players]);
break;
case player_muted:
lua_pushboolean(L, plr->muted);
break;
case player_fovadd:
lua_pushfixed(L, plr->fovadd);
break;
......@@ -1359,6 +1364,11 @@ static int player_set(lua_State *L)
case player_lastinputtime:
plr->lastinputtime = (tic_t)luaL_checkinteger(L, 3);
break;
case player_ping:
return NOSET;
case player_muted:
plr->muted = lua_toboolean(L, 3);
break;
case player_fovadd:
plr->fovadd = luaL_checkfixed(L, 3);
break;
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by LJ Sonic
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file lua_quaternionlib.c
/// \brief quaternion library for Lua scripting
#include "quaternion.h"
#include "lua_script.h"
#include "lua_libs.h"
static quaternion_t *NewQuaternion(lua_State *L)
{
quaternion_t *quat = lua_newuserdata(L, sizeof(*quat));
luaL_getmetatable(L, META_QUATERNION);
lua_setmetatable(L, -2);
return quat;
}
////////////////////
// STATIC MEMBERS //
////////////////////
static int quaternion_new(lua_State *L)
{
Quaternion_SetIdentity(NewQuaternion(L));
return 1;
}
static int quaternion_fromAxisRotation(lua_State *L)
{
vector3_t *axis = luaL_checkudata(L, 1, META_VECTOR3);
fixed_t angle = luaL_checkfixed(L, 2);
Quaternion_SetAxisRotation(NewQuaternion(L), axis, angle);
return 1;
}
static luaL_Reg quaternion[] = {
{"new", quaternion_new},
{"fromAxisRotation", quaternion_fromAxisRotation},
{NULL, NULL}
};
/////////////
// MEMBERS //
/////////////
static int quaternion_clone(lua_State *L)
{
quaternion_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
Quaternion_Copy(NewQuaternion(L), quat);
return 1;
}
static int quaternion_toMatrix(lua_State *L)
{
quaternion_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
matrix_t *mat = lua_newuserdata(L, sizeof(*mat));
luaL_getmetatable(L, META_MATRIX);
lua_setmetatable(L, -2);
Quaternion_ToMatrix(mat, quat);
return 1;
}
enum quaternionfield_e {
quaternionfield_clone = 0,
quaternionfield_toMatrix,
quaternionfield_x,
quaternionfield_y,
quaternionfield_z,
quaternionfield_w,
};
static const char *const quaternionfield_opt[] = {
"clone",
"toMatrix",
"x",
"y",
"z",
"w",
NULL};
static int quaternion_get(lua_State *L)
{
quaternion_t *quat = luaL_checkudata(L, 1, META_QUATERNION);
enum quaternionfield_e field = luaL_checkoption(L, 2, quaternionfield_opt[0], quaternionfield_opt);
switch(field)
{
case quaternionfield_clone: lua_pushcfunction(L, quaternion_clone); return 1;
case quaternionfield_toMatrix: lua_pushcfunction(L, quaternion_toMatrix); return 1;
case quaternionfield_x: lua_pushfixed(L, quat->x); return 1;
case quaternionfield_y: lua_pushfixed(L, quat->y); return 1;
case quaternionfield_z: lua_pushfixed(L, quat->z); return 1;
case quaternionfield_w: lua_pushfixed(L, quat->w); return 1;
default: break;
}
return 0;
}
///////////////
// OPERATORS //
///////////////
static int quaternion_mul(lua_State *L)
{
quaternion_t *quat1 = luaL_checkudata(L, 1, META_QUATERNION);
quaternion_t *quat2 = luaL_checkudata(L, 2, META_QUATERNION);
Quaternion_Mul(NewQuaternion(L), quat1, quat2);
return 1;
}
int LUA_QuaternionLib(lua_State *L)
{
luaL_newmetatable(L, META_QUATERNION);
LUA_SetCFunctionField(L, "__index", quaternion_get);
LUA_SetCFunctionField(L, "__mul", quaternion_mul);
lua_pop(L, 1);
luaL_register(L, "Quaternion", quaternion);
return 0;
}
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -20,6 +20,7 @@
#include "r_state.h"
#include "r_sky.h"
#include "g_game.h"
#include "g_demo.h"
#include "g_input.h"
#include "f_finale.h"
#include "byteptr.h"
......@@ -62,6 +63,10 @@ static lua_CFunction liblist[] = {
LUA_HudLib, // HUD stuff
LUA_ColorLib, // general color functions
LUA_InputLib, // inputs
LUA_InterceptLib, // intercept_t
LUA_VectorLib, // vectors
LUA_MatrixLib, // matrices
LUA_QuaternionLib, // quaternions
NULL
};
......@@ -274,6 +279,18 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"tutorialmode")) {
lua_pushboolean(L, tutorialmode);
return 1;
} else if (fastcmp(word,"keepcutscene")) {
lua_pushboolean(L, keepcutscene);
return 1;
} else if (fastcmp(word,"nextgametype")) {
lua_pushinteger(L, nextgametype);
return 1;
} else if (fastcmp(word,"skipstats")) {
lua_pushinteger(L, skipstats);
return 1;
} else if (fastcmp(word,"nextmapoverride")) {
lua_pushinteger(L, nextmapoverride);
return 1;
// end map vars
// begin CTF colors
} else if (fastcmp(word,"skincolor_redteam")) {
......@@ -394,6 +411,22 @@ int LUA_PushGlobals(lua_State *L, const char *word)
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
// demos booleans
} else if (fastcmp(word, "demoplayback")) {
lua_pushboolean(L, demoplayback);
return 1;
} else if (fastcmp(word, "titledemo")) {
lua_pushboolean(L, titledemo);
return 1;
} else if (fastcmp(word, "demorecording")) {
lua_pushboolean(L, demorecording);
return 1;
} else if (fastcmp(word, "timingdemo")) {
lua_pushboolean(L, timingdemo);
return 1;
} else if (fastcmp(word, "demosynced")) {
lua_pushboolean(L, demosynced);
return 1;
} else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds);
return 1;
......@@ -412,6 +445,18 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "token")) {
lua_pushinteger(L, token);
return 1;
} else if (fastcmp(word, "emblems")) {
lua_pushinteger(L, M_CountEmblems(clientGamedata));
return 1;
} else if (fastcmp(word, "numemblems")) {
lua_pushinteger(L, numemblems);
return 1;
} else if (fastcmp(word, "numextraemblems")) {
lua_pushinteger(L, numextraemblems);
return 1;
} else if (fastcmp(word, "nummaprings")) {
lua_pushinteger(L, nummaprings);
return 1;
} else if (fastcmp(word, "gamestate")) {
lua_pushinteger(L, gamestate);
return 1;
......@@ -437,6 +482,14 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "chatactive")) {
lua_pushboolean(L, chat_on);
return 1;
} else if (fastcmp(word, "currentsaveslot")) {
if (multiplayer)
return 0;
lua_pushinteger(L, cursaveslot);
return 1;
} else if (fastcmp(word, "gamedatafilename")) {
lua_pushstring(L, strcmp(timeattackfolder, "main") ? timeattackfolder : "gamedata");
return 1;
}
return 0;
}
......@@ -460,6 +513,8 @@ int LUA_CheckGlobals(lua_State *L, const char *word)
emeralds = (UINT16)luaL_checkinteger(L, 2);
else if (fastcmp(word, "token"))
token = (UINT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "nummaprings"))
nummaprings = (INT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "gravity"))
gravity = (fixed_t)luaL_checkinteger(L, 2);
else if (fastcmp(word, "stoppedclock"))
......@@ -977,16 +1032,6 @@ void LUA_InvalidateLevel(void)
LUA_InvalidateUserdata(&slope->o);
LUA_InvalidateUserdata(&slope->d);
}
#ifdef HAVE_LUA_SEGS
for (i = 0; i < numsegs; i++)
LUA_InvalidateUserdata(&segs[i]);
for (i = 0; i < numnodes; i++)
{
LUA_InvalidateUserdata(&nodes[i]);
LUA_InvalidateUserdata(nodes[i].bbox);
LUA_InvalidateUserdata(nodes[i].children);
}
#endif
}
void LUA_InvalidateMapthings(void)
......@@ -1013,743 +1058,6 @@ void LUA_InvalidatePlayer(player_t *player)
LUA_InvalidateUserdata(&player->cmd);
}
enum
{
ARCH_NULL=0,
ARCH_TRUE,
ARCH_FALSE,
ARCH_INT8,
ARCH_INT16,
ARCH_INT32,
ARCH_SMALLSTRING,
ARCH_LARGESTRING,
ARCH_TABLE,
ARCH_MOBJINFO,
ARCH_STATE,
ARCH_MOBJ,
ARCH_PLAYER,
ARCH_MAPTHING,
ARCH_VERTEX,
ARCH_LINE,
ARCH_SIDE,
ARCH_SUBSECTOR,
ARCH_SECTOR,
#ifdef HAVE_LUA_SEGS
ARCH_SEG,
ARCH_NODE,
#endif
ARCH_FFLOOR,
ARCH_POLYOBJ,
ARCH_SLOPE,
ARCH_MAPHEADER,
ARCH_SKINCOLOR,
ARCH_MOUSE,
ARCH_SKIN,
ARCH_TEND=0xFF,
};
static const struct {
const char *meta;
UINT8 arch;
} meta2arch[] = {
{META_MOBJINFO, ARCH_MOBJINFO},
{META_STATE, ARCH_STATE},
{META_MOBJ, ARCH_MOBJ},
{META_PLAYER, ARCH_PLAYER},
{META_MAPTHING, ARCH_MAPTHING},
{META_VERTEX, ARCH_VERTEX},
{META_LINE, ARCH_LINE},
{META_SIDE, ARCH_SIDE},
{META_SUBSECTOR,ARCH_SUBSECTOR},
{META_SECTOR, ARCH_SECTOR},
#ifdef HAVE_LUA_SEGS
{META_SEG, ARCH_SEG},
{META_NODE, ARCH_NODE},
#endif
{META_FFLOOR, ARCH_FFLOOR},
{META_POLYOBJ, ARCH_POLYOBJ},
{META_SLOPE, ARCH_SLOPE},
{META_MAPHEADER, ARCH_MAPHEADER},
{META_SKINCOLOR, ARCH_SKINCOLOR},
{META_MOUSE, ARCH_MOUSE},
{META_SKIN, ARCH_SKIN},
{NULL, ARCH_NULL}
};
static UINT8 GetUserdataArchType(int index)
{
UINT8 i;
lua_getmetatable(gL, index);
for (i = 0; meta2arch[i].meta; i++)
{
luaL_getmetatable(gL, meta2arch[i].meta);
if (lua_rawequal(gL, -1, -2))
{
lua_pop(gL, 2);
return meta2arch[i].arch;
}
lua_pop(gL, 1);
}
lua_pop(gL, 1);
return ARCH_NULL;
}
static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{
if (myindex < 0)
myindex = lua_gettop(gL)+1+myindex;
switch (lua_type(gL, myindex))
{
case LUA_TNONE:
case LUA_TNIL:
WRITEUINT8(save_p, ARCH_NULL);
break;
// This might be a problem. D:
case LUA_TLIGHTUSERDATA:
case LUA_TTHREAD:
case LUA_TFUNCTION:
WRITEUINT8(save_p, ARCH_NULL);
return 2;
case LUA_TBOOLEAN:
WRITEUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE);
break;
case LUA_TNUMBER:
{
lua_Integer number = lua_tointeger(gL, myindex);
if (number >= INT8_MIN && number <= INT8_MAX)
{
WRITEUINT8(save_p, ARCH_INT8);
WRITESINT8(save_p, number);
}
else if (number >= INT16_MIN && number <= INT16_MAX)
{
WRITEUINT8(save_p, ARCH_INT16);
WRITEINT16(save_p, number);
}
else
{
WRITEUINT8(save_p, ARCH_INT32);
WRITEFIXED(save_p, number);
}
break;
}
case LUA_TSTRING:
{
UINT32 len = (UINT32)lua_objlen(gL, myindex); // get length of string, including embedded zeros
const char *s = lua_tostring(gL, myindex);
UINT32 i = 0;
// if you're wondering why we're writing a string to save_p this way,
// it turns out that Lua can have embedded zeros ('\0') in the strings,
// so we can't use WRITESTRING as that cuts off when it finds a '\0'.
// Saving the size of the string also allows us to get the size of the string on the other end,
// fixing the awful crashes previously encountered for reading strings longer than 1024
// (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?)
// -- Monster Iestyn 05/08/18
if (len < 255)
{
WRITEUINT8(save_p, ARCH_SMALLSTRING);
WRITEUINT8(save_p, len); // save size of string
}
else
{
WRITEUINT8(save_p, ARCH_LARGESTRING);
WRITEUINT32(save_p, len); // save size of string
}
while (i < len)
WRITECHAR(save_p, s[i++]); // write chars individually, including the embedded zeros
break;
}
case LUA_TTABLE:
{
boolean found = false;
INT32 i;
UINT16 t = (UINT16)lua_objlen(gL, TABLESINDEX);
for (i = 1; i <= t && !found; i++)
{
lua_rawgeti(gL, TABLESINDEX, i);
if (lua_rawequal(gL, myindex, -1))
{
t = i;
found = true;
}
lua_pop(gL, 1);
}
if (!found)
{
t++;
if (t == 0)
{
CONS_Alert(CONS_ERROR, "Too many tables to archive!\n");
WRITEUINT8(save_p, ARCH_NULL);
return 0;
}
}
WRITEUINT8(save_p, ARCH_TABLE);
WRITEUINT16(save_p, t);
if (!found)
{
lua_pushvalue(gL, myindex);
lua_rawseti(gL, TABLESINDEX, t);
return 1;
}
break;
}
case LUA_TUSERDATA:
switch (GetUserdataArchType(myindex))
{
case ARCH_MOBJINFO:
{
mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOBJINFO);
WRITEUINT16(save_p, info - mobjinfo);
break;
}
case ARCH_STATE:
{
state_t *state = *((state_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_STATE);
WRITEUINT16(save_p, state - states);
break;
}
case ARCH_MOBJ:
{
mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex));
if (!mobj)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_MOBJ);
WRITEUINT32(save_p, mobj->mobjnum);
}
break;
}
case ARCH_PLAYER:
{
player_t *player = *((player_t **)lua_touserdata(gL, myindex));
if (!player)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_PLAYER);
WRITEUINT8(save_p, player - players);
}
break;
}
case ARCH_MAPTHING:
{
mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex));
if (!mapthing)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_MAPTHING);
WRITEUINT16(save_p, mapthing - mapthings);
}
break;
}
case ARCH_VERTEX:
{
vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex));
if (!vertex)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_VERTEX);
WRITEUINT16(save_p, vertex - vertexes);
}
break;
}
case ARCH_LINE:
{
line_t *line = *((line_t **)lua_touserdata(gL, myindex));
if (!line)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_LINE);
WRITEUINT16(save_p, line - lines);
}
break;
}
case ARCH_SIDE:
{
side_t *side = *((side_t **)lua_touserdata(gL, myindex));
if (!side)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SIDE);
WRITEUINT16(save_p, side - sides);
}
break;
}
case ARCH_SUBSECTOR:
{
subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex));
if (!subsector)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SUBSECTOR);
WRITEUINT16(save_p, subsector - subsectors);
}
break;
}
case ARCH_SECTOR:
{
sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex));
if (!sector)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SECTOR);
WRITEUINT16(save_p, sector - sectors);
}
break;
}
#ifdef HAVE_LUA_SEGS
case ARCH_SEG:
{
seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex));
if (!seg)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SEG);
WRITEUINT16(save_p, seg - segs);
}
break;
}
case ARCH_NODE:
{
node_t *node = *((node_t **)lua_touserdata(gL, myindex));
if (!node)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_NODE);
WRITEUINT16(save_p, node - nodes);
}
break;
}
#endif
case ARCH_FFLOOR:
{
ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex));
if (!rover)
WRITEUINT8(save_p, ARCH_NULL);
else {
UINT16 i = P_GetFFloorID(rover);
if (i == UINT16_MAX) // invalid ID
WRITEUINT8(save_p, ARCH_NULL);
else
{
WRITEUINT8(save_p, ARCH_FFLOOR);
WRITEUINT16(save_p, rover->target - sectors);
WRITEUINT16(save_p, i);
}
}
break;
}
case ARCH_POLYOBJ:
{
polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex));
if (!polyobj)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_POLYOBJ);
WRITEUINT16(save_p, polyobj-PolyObjects);
}
break;
}
case ARCH_SLOPE:
{
pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex));
if (!slope)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SLOPE);
WRITEUINT16(save_p, slope->id);
}
break;
}
case ARCH_MAPHEADER:
{
mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
if (!header)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_MAPHEADER);
WRITEUINT16(save_p, header - *mapheaderinfo);
}
break;
}
case ARCH_SKINCOLOR:
{
skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKINCOLOR);
WRITEUINT16(save_p, info - skincolors);
break;
}
case ARCH_MOUSE:
{
mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOUSE);
WRITEUINT8(save_p, m == &mouse ? 1 : 2);
break;
}
case ARCH_SKIN:
{
skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKIN);
WRITEUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256
break;
}
default:
WRITEUINT8(save_p, ARCH_NULL);
return 2;
}
break;
}
return 0;
}
static void ArchiveExtVars(void *pointer, const char *ptype)
{
int TABLESINDEX;
UINT16 i;
if (!gL) {
if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0);
return;
}
TABLESINDEX = lua_gettop(gL);
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(gL, -1));
lua_pushlightuserdata(gL, pointer);
lua_rawget(gL, -2);
lua_remove(gL, -2); // pop LREG_EXTVARS
if (!lua_istable(gL, -1))
{ // no extra values table
lua_pop(gL, 1);
if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0);
return;
}
lua_pushnil(gL);
for (i = 0; lua_next(gL, -2); i++)
lua_pop(gL, 1);
// skip anything that has an empty table and isn't a player.
if (i == 0)
{
if (fastcmp(ptype,"player")) // always include players even if they have no extra variables
WRITEUINT16(save_p, 0);
lua_pop(gL, 1);
return;
}
if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header
WRITEUINT32(save_p, ((mobj_t *)pointer)->mobjnum);
WRITEUINT16(save_p, i);
lua_pushnil(gL);
while (lua_next(gL, -2))
{
I_Assert(lua_type(gL, -2) == LUA_TSTRING);
WRITESTRING(save_p, lua_tostring(gL, -2));
if (ArchiveValue(TABLESINDEX, -1) == 2)
CONS_Alert(CONS_ERROR, "Type of value for %s entry '%s' (%s) could not be archived!\n", ptype, lua_tostring(gL, -2), luaL_typename(gL, -1));
lua_pop(gL, 1);
}
lua_pop(gL, 1);
}
static int NetArchive(lua_State *L)
{
int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L);
for (i = 1; i <= n; i++)
ArchiveValue(TABLESINDEX, i);
return n;
}
static void ArchiveTables(void)
{
int TABLESINDEX;
UINT16 i, n;
UINT8 e;
if (!gL)
return;
TABLESINDEX = lua_gettop(gL);
n = (UINT16)lua_objlen(gL, TABLESINDEX);
for (i = 1; i <= n; i++)
{
lua_rawgeti(gL, TABLESINDEX, i);
lua_pushnil(gL);
while (lua_next(gL, -2))
{
// Write key
e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
if (e == 1)
n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise)
CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -2), luaL_typename(gL, -2), i);
// Write value
e = ArchiveValue(TABLESINDEX, -1);
if (e == 1)
n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid value type
CONS_Alert(CONS_ERROR, "Type of value for table %d entry '%s' (%s) could not be archived!\n", i, lua_tostring(gL, -2), luaL_typename(gL, -1));
lua_pop(gL, 1);
}
WRITEUINT8(save_p, ARCH_TEND);
// Write metatable ID
if (lua_getmetatable(gL, -1))
{
// registry.metatables[metatable]
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_pushvalue(gL, -2);
lua_gettable(gL, -2);
WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1));
lua_pop(gL, 3);
}
else
WRITEUINT16(save_p, 0);
lua_pop(gL, 1);
}
}
static UINT8 UnArchiveValue(int TABLESINDEX)
{
UINT8 type = READUINT8(save_p);
switch (type)
{
case ARCH_NULL:
lua_pushnil(gL);
break;
case ARCH_TRUE:
lua_pushboolean(gL, true);
break;
case ARCH_FALSE:
lua_pushboolean(gL, false);
break;
case ARCH_INT8:
lua_pushinteger(gL, READSINT8(save_p));
break;
case ARCH_INT16:
lua_pushinteger(gL, READINT16(save_p));
break;
case ARCH_INT32:
lua_pushinteger(gL, READFIXED(save_p));
break;
case ARCH_SMALLSTRING:
case ARCH_LARGESTRING:
{
UINT32 len;
char *value;
UINT32 i = 0;
// See my comments in the ArchiveValue function;
// it's much the same for reading strings as writing them!
// (i.e. we can't use READSTRING either)
// -- Monster Iestyn 05/08/18
if (type == ARCH_SMALLSTRING)
len = READUINT8(save_p); // length of string, including embedded zeros
else
len = READUINT32(save_p); // length of string, including embedded zeros
value = malloc(len); // make temp buffer of size len
// now read the actual string
while (i < len)
value[i++] = READCHAR(save_p); // read chars individually, including the embedded zeros
lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros)
free(value); // free the buffer
break;
}
case ARCH_TABLE:
{
UINT16 tid = READUINT16(save_p);
lua_rawgeti(gL, TABLESINDEX, tid);
if (lua_isnil(gL, -1))
{
lua_pop(gL, 1);
lua_newtable(gL);
lua_pushvalue(gL, -1);
lua_rawseti(gL, TABLESINDEX, tid);
return 2;
}
break;
}
case ARCH_MOBJINFO:
LUA_PushUserdata(gL, &mobjinfo[READUINT16(save_p)], META_MOBJINFO);
break;
case ARCH_STATE:
LUA_PushUserdata(gL, &states[READUINT16(save_p)], META_STATE);
break;
case ARCH_MOBJ:
LUA_PushUserdata(gL, P_FindNewPosition(READUINT32(save_p)), META_MOBJ);
break;
case ARCH_PLAYER:
LUA_PushUserdata(gL, &players[READUINT8(save_p)], META_PLAYER);
break;
case ARCH_MAPTHING:
LUA_PushUserdata(gL, &mapthings[READUINT16(save_p)], META_MAPTHING);
break;
case ARCH_VERTEX:
LUA_PushUserdata(gL, &vertexes[READUINT16(save_p)], META_VERTEX);
break;
case ARCH_LINE:
LUA_PushUserdata(gL, &lines[READUINT16(save_p)], META_LINE);
break;
case ARCH_SIDE:
LUA_PushUserdata(gL, &sides[READUINT16(save_p)], META_SIDE);
break;
case ARCH_SUBSECTOR:
LUA_PushUserdata(gL, &subsectors[READUINT16(save_p)], META_SUBSECTOR);
break;
case ARCH_SECTOR:
LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_SECTOR);
break;
#ifdef HAVE_LUA_SEGS
case ARCH_SEG:
LUA_PushUserdata(gL, &segs[READUINT16(save_p)], META_SEG);
break;
case ARCH_NODE:
LUA_PushUserdata(gL, &nodes[READUINT16(save_p)], META_NODE);
break;
#endif
case ARCH_FFLOOR:
{
sector_t *sector = &sectors[READUINT16(save_p)];
UINT16 id = READUINT16(save_p);
ffloor_t *rover = P_GetFFloorByID(sector, id);
if (rover)
LUA_PushUserdata(gL, rover, META_FFLOOR);
break;
}
case ARCH_POLYOBJ:
LUA_PushUserdata(gL, &PolyObjects[READUINT16(save_p)], META_POLYOBJ);
break;
case ARCH_SLOPE:
LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE);
break;
case ARCH_MAPHEADER:
LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER);
break;
case ARCH_SKINCOLOR:
LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR);
break;
case ARCH_MOUSE:
LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE);
break;
case ARCH_SKIN:
LUA_PushUserdata(gL, skins[READUINT8(save_p)], META_SKIN);
break;
case ARCH_TEND:
return 1;
}
return 0;
}
static void UnArchiveExtVars(void *pointer)
{
int TABLESINDEX;
UINT16 field_count = READUINT16(save_p);
UINT16 i;
char field[1024];
if (field_count == 0)
return;
I_Assert(gL != NULL);
TABLESINDEX = lua_gettop(gL);
lua_createtable(gL, 0, field_count); // pointer's ext vars subtable
for (i = 0; i < field_count; i++)
{
READSTRING(save_p, field);
UnArchiveValue(TABLESINDEX);
lua_setfield(gL, -2, field);
}
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(gL, -1));
lua_pushlightuserdata(gL, pointer);
lua_pushvalue(gL, -3); // pointer's ext vars subtable
lua_rawset(gL, -3);
lua_pop(gL, 2); // pop LREG_EXTVARS and pointer's subtable
}
static int NetUnArchive(lua_State *L)
{
int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L);
for (i = 1; i <= n; i++)
UnArchiveValue(TABLESINDEX);
return n;
}
static void UnArchiveTables(void)
{
int TABLESINDEX;
UINT16 i, n;
UINT16 metatableid;
if (!gL)
return;
TABLESINDEX = lua_gettop(gL);
n = (UINT16)lua_objlen(gL, TABLESINDEX);
for (i = 1; i <= n; i++)
{
lua_rawgeti(gL, TABLESINDEX, i);
while (true)
{
UINT8 e = UnArchiveValue(TABLESINDEX); // read key
if (e == 1) // End of table
break;
else if (e == 2) // Key contains a new table
n++;
if (UnArchiveValue(TABLESINDEX) == 2) // read value
n++;
if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved)
{
CONS_Alert(CONS_ERROR, "A nil key in table %d was found! (Invalid key type or corrupted save?)\n", i);
lua_pop(gL, 2); // pop key and value instead of setting them in the table, to prevent Lua panic errors
}
else
lua_rawset(gL, -3);
}
metatableid = READUINT16(save_p);
if (metatableid)
{
// setmetatable(table, registry.metatables[metatableid])
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_rawgeti(gL, -1, metatableid);
if (lua_isnil(gL, -1))
I_Error("Unknown metatable ID %d\n", metatableid);
lua_setmetatable(gL, -3);
lua_pop(gL, 1);
}
lua_pop(gL, 1);
}
}
void LUA_Step(void)
{
if (!gL)
......@@ -1758,76 +1066,6 @@ void LUA_Step(void)
lua_gc(gL, LUA_GCSTEP, 1);
}
void LUA_Archive(void)
{
INT32 i;
thinker_t *th;
if (gL)
lua_newtable(gL); // tables to be archived.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] && i > 0) // dedicated servers...
continue;
// all players in game will be archived, even if they just add a 0.
ArchiveExtVars(&players[i], "player");
}
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
// archive function will determine when to skip mobjs,
// and write mobjnum in otherwise.
ArchiveExtVars(th, "mobj");
}
WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode
ArchiveTables();
if (gL)
lua_pop(gL, 1); // pop tables
}
void LUA_UnArchive(void)
{
UINT32 mobjnum;
INT32 i;
thinker_t *th;
if (gL)
lua_newtable(gL); // tables to be read
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] && i > 0) // dedicated servers...
continue;
UnArchiveExtVars(&players[i]);
}
do {
mobjnum = READUINT32(save_p); // read a mobjnum
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
continue;
UnArchiveExtVars(th); // apply variables
}
} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode
UnArchiveTables();
if (gL)
lua_pop(gL, 1); // pop tables
}
// For mobj_t, player_t, etc. to take custom variables.
int Lua_optoption(lua_State *L, int narg, int def, int list_ref)
{
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -13,6 +13,7 @@
#ifndef LUA_SCRIPT_H
#define LUA_SCRIPT_H
#include "p_saveg.h"
#include "m_fixed.h"
#include "doomtype.h"
#include "d_player.h"
......@@ -29,7 +30,9 @@
// fixed_t casting
// TODO add some distinction between fixed numbers and integer numbers
// for at least the purpose of printing and maybe math.
#define lua_tofixed(L, i) lua_tointeger(L, i)
#define luaL_checkfixed(L, i) luaL_checkinteger(L, i)
#define luaL_optfixed(L, i, d) luaL_optinteger(L, i, d)
#define lua_pushfixed(L, f) lua_pushinteger(L, f)
// angle_t casting
......@@ -52,15 +55,12 @@ void LUA_DumpFile(const char *filename);
#endif
fixed_t LUA_EvalMath(const char *word);
void LUA_Step(void);
void LUA_Archive(void);
void LUA_UnArchive(void);
int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_CheckGlobals(lua_State *L, const char *word);
void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
void LUA_CVarChanged(void *cvar); // lua_consolelib.c
int Lua_optoption(lua_State *L, int narg, int def, int list_ref);
int Lua_CreateFieldTable(lua_State *L, const char *const lst[]);
void LUA_HookNetArchive(lua_CFunction archFunc);
void LUA_PushTaggableObjectArray
( lua_State *L,
......@@ -162,9 +162,6 @@ void COM_Lua_f(void);
}\
}
// uncomment if you want seg_t/node_t in Lua
// #define HAVE_LUA_SEGS
#define ISINLEVEL \
(gamestate == GS_LEVEL || titlemapinaction)
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2014-2016 by John "JTE" Muniz.
// Copyright (C) 2014-2023 by Sonic Team Junior.
// Copyright (C) 2014-2025 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -54,7 +54,8 @@ enum skin {
skin_contspeed,
skin_contangle,
skin_soundsid,
skin_sprites,
skin_sprites, // TODO: 2.3: Delete
skin_skinsprites,
skin_supersprites,
skin_natkcolor
};
......@@ -95,7 +96,8 @@ static const char *const skin_opt[] = {
"contspeed",
"contangle",
"soundsid",
"sprites",
"sprites", // TODO: 2.3: Delete
"skinsprites",
"supersprites",
"natkcolor",
NULL};
......@@ -219,7 +221,10 @@ static int skin_get(lua_State *L)
case skin_soundsid:
LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID);
break;
case skin_sprites:
case skin_sprites: // TODO: 2.3: Delete
LUA_PushUserdata(L, skin->sprites_compat, META_SKINSPRITESCOMPAT);
break;
case skin_skinsprites:
LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES);
break;
case skin_supersprites:
......@@ -338,15 +343,7 @@ static int soundsid_num(lua_State *L)
return 1;
}
enum spritesopt {
numframes = 0
};
static const char *const sprites_opt[] = {
"numframes",
NULL};
// skin.sprites[i] -> sprites[i]
// skin.skinsprites[i] -> sprites[i]
static int lib_getSkinSprite(lua_State *L)
{
spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES);
......@@ -359,13 +356,46 @@ static int lib_getSkinSprite(lua_State *L)
return 1;
}
// #skin.sprites -> NUMPLAYERSPRITES
// #skin.skinsprites -> NUMPLAYERSPRITES
static int lib_numSkinsSprites(lua_State *L)
{
lua_pushinteger(L, NUMPLAYERSPRITES);
return 1;
}
// TODO: 2.3: Delete
// skin.sprites[i] -> sprites[i]
static int lib_getSkinSpriteCompat(lua_State *L)
{
spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESCOMPAT);
INT32 i = luaL_checkinteger(L, 2) & (SPR2F_MASK | SPR2F_SUPER);
if (i & SPR2F_SUPER)
i = (i & ~SPR2F_SUPER) + NUMPLAYERSPRITES;
if (i < 0 || i >= NUMPLAYERSPRITES*2)
return luaL_error(L, "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)
{
spritedef_t *sprite = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESLIST);
......@@ -387,6 +417,7 @@ int LUA_SkinLib(lua_State *L)
LUA_RegisterUserdataMetatable(L, META_SOUNDSID, soundsid_get, NULL, soundsid_num);
LUA_RegisterUserdataMetatable(L, META_SKINSPRITES, lib_getSkinSprite, NULL, lib_numSkinsSprites);
LUA_RegisterUserdataMetatable(L, META_SKINSPRITESLIST, sprite_get, NULL, NULL);
LUA_RegisterUserdataMetatable(L, META_SKINSPRITESCOMPAT, lib_getSkinSpriteCompat, NULL, lib_numSkinsSpritesCompat); // TODO: 2.3: Delete
skin_fields_ref = Lua_CreateFieldTable(L, skin_opt);
......
......@@ -44,7 +44,7 @@ static int iterationState_gc(lua_State *L)
}
#define push_thinker(th) {\
if ((th)->function.acp1 == (actionf_p1)P_MobjThinker) \
if ((th)->function == (actionf_p1)P_MobjThinker) \
LUA_PushUserdata(L, (th), META_MOBJ); \
else \
lua_pushlightuserdata(L, (th)); \
......@@ -93,7 +93,7 @@ static int lib_iterateThinkers(lua_State *L)
return luaL_error(L, "next thinker invalidated during iteration");
for (; next != &thlist[THINK_MOBJ]; next = next->next)
if (!it->filter || next->function.acp1 == it->filter)
if (!it->filter || next->function == it->filter)
{
push_thinker(next);
if (next->next != &thlist[THINK_MOBJ])
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by LJ Sonic
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file lua_vectorlib.c
/// \brief vector library for Lua scripting
#include "vector3d.h"
#include "lua_script.h"
#include "lua_libs.h"
// shared by both Vector2D and Vector3D
enum vectorfield_e {
vectorfield_clone = 0,
vectorfield_opposite,
vectorfield_x,
vectorfield_y,
vectorfield_z,
vectorfield_length,
vectorfield_normalized,
};
static const char *const vectorfield_opt[] = {
"vector_clone",
"vector_opposite",
"x",
"y",
"z",
"vector_length",
"vector_normalized",
NULL};
////////////////////////////
// VECTOR2 STATIC MEMBERS //
////////////////////////////
/////////////////////
// VECTOR2 MEMBERS //
/////////////////////
static int vector2d_get(lua_State *L)
{
vector2_t *vec = *((vector2_t **)luaL_checkudata(L, 1, META_VECTOR2));
enum vectorfield_e field = luaL_checkoption(L, 2, vectorfield_opt[0], vectorfield_opt);
switch(field)
{
case vectorfield_x: lua_pushfixed(L, vec->x); return 1;
case vectorfield_y: lua_pushfixed(L, vec->y); return 1;
default: break;
}
return 0;
}
/////////////
// VECTOR3 //
/////////////
static vector3_t *NewVector3(lua_State *L)
{
vector3_t *vec = lua_newuserdata(L, sizeof(*vec));
luaL_getmetatable(L, META_VECTOR3);
lua_setmetatable(L, -2);
return vec;
}
////////////////////////////
// VECTOR3 STATIC MEMBERS //
////////////////////////////
static int vector3d_new(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_optfixed(L, 3, 0);
Vector3D_Set(NewVector3(L), x, y, z);
return 1;
}
static luaL_Reg vector3d[] = {
{"new", vector3d_new},
{NULL, NULL}
};
/////////////////////
// VECTOR3 MEMBERS //
/////////////////////
static int vector3d_clone(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
Vector3D_Copy(NewVector3(L), vec);
return 1;
}
static int vector3d_opposite(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
Vector3D_Opposite(NewVector3(L), vec);
return 1;
}
static int vector3d_get(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
enum vectorfield_e field = luaL_checkoption(L, 2, vectorfield_opt[0], vectorfield_opt);
if (!vec)
return luaL_error(L, "accessed vector3_t doesn't exist anymore.");
switch(field)
{
case vectorfield_clone: lua_pushcfunction(L, vector3d_clone); return 1;
case vectorfield_opposite: lua_pushcfunction(L, vector3d_opposite); return 1;
case vectorfield_x: lua_pushfixed(L, vec->x); return 1;
case vectorfield_y: lua_pushfixed(L, vec->y); return 1;
case vectorfield_z: lua_pushfixed(L, vec->z); return 1;
case vectorfield_length: lua_pushfixed(L, Vector3D_Length(vec)); return 1;
case vectorfield_normalized: Vector3D_Normalize(NewVector3(L), vec); return 1;
default: break;
}
return 0;
}
///////////////////////
// VECTOR3 OPERATORS //
///////////////////////
static int vector3d_eq(lua_State *L)
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
lua_pushboolean(L, Vector3D_Equal(vec1, vec2));
return 1;
}
static int vector3d_op(
lua_State *L,
vector3_t *(*opvector)(vector3_t*, vector3_t*, vector3_t*),
vector3_t *(*opfixed)(vector3_t*, vector3_t*, fixed_t)
)
{
if (lua_isnumber(L, 1) && (opfixed == Vector3D_AddFixed || opfixed == Vector3D_MulFixed))
{
fixed_t n1 = lua_tofixed(L, 1);
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
opfixed(NewVector3(L), vec2, n1);
}
else if (lua_isnumber(L, 2))
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
fixed_t n2 = lua_tofixed(L, 2);
opfixed(NewVector3(L), vec1, n2);
}
else
{
vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3);
vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3);
opvector(NewVector3(L), vec1, vec2);
}
return 1;
}
static int vector3d_add(lua_State *L)
{
return vector3d_op(L, Vector3D_Add, Vector3D_AddFixed);
}
static int vector3d_sub(lua_State *L)
{
return vector3d_op(L, Vector3D_Sub, Vector3D_SubFixed);
}
static int vector3d_mul(lua_State *L)
{
return vector3d_op(L, Vector3D_Mul, Vector3D_MulFixed);
}
static int vector3d_div(lua_State *L)
{
return vector3d_op(L, Vector3D_Div, Vector3D_DivFixed);
}
static int vector3d_unm(lua_State *L)
{
vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3);
Vector3D_Opposite(NewVector3(L), vec);
return 1;
}
int LUA_VectorLib(lua_State *L)
{
LUA_RegisterUserdataMetatable(L, META_VECTOR2, vector2d_get, NULL, NULL);
luaL_newmetatable(L, META_VECTOR3);
LUA_SetCFunctionField(L, "__index", vector3d_get);
LUA_SetCFunctionField(L, "__eq", vector3d_eq);
LUA_SetCFunctionField(L, "__add", vector3d_add);
LUA_SetCFunctionField(L, "__sub", vector3d_sub);
LUA_SetCFunctionField(L, "__mul", vector3d_mul);
LUA_SetCFunctionField(L, "__div", vector3d_div);
LUA_SetCFunctionField(L, "__unm", vector3d_unm);
lua_pop(L, 1);
luaL_register(L, "Vector3D", vector3d);
return 0;
}
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2025 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -20,8 +20,7 @@
typedef struct aatree_node_s
{
INT32 level;
INT32 key;
void* key;
void* value;
struct aatree_node_s *left, *right;
......@@ -43,8 +42,10 @@ aatree_t *M_AATreeAlloc(UINT32 flags)
static void M_AATreeFree_Node(aatree_node_t *node)
{
if (node->left) M_AATreeFree_Node(node->left);
if (node->right) M_AATreeFree_Node(node->right);
if (node->left)
M_AATreeFree_Node(node->left);
if (node->right)
M_AATreeFree_Node(node->right);
Z_Free(node);
}
......@@ -56,108 +57,132 @@ void M_AATreeFree(aatree_t *aatree)
Z_Free(aatree);
}
static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
static aatree_node_t *M_AATreeRotateRight(aatree_node_t *node)
{
if (node && node->left && node->left->level == node->level)
{
// Not allowed: horizontal left-link. Reverse the
// horizontal link and hook the orphan back in.
aatree_node_t *oldleft = node->left;
node->left = oldleft->right;
oldleft->right = node;
return oldleft;
aatree_node_t *newnode = node->left;
newnode->right = node;
node->left = NULL;
return newnode;
}
// No change needed.
return node;
static aatree_node_t *M_AATreeRotateLeft(aatree_node_t *node)
{
aatree_node_t *newnode = node->right;
newnode->left = node;
node->right = NULL;
return newnode;
}
static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
static aatree_node_t *M_AATreeRebalance(aatree_node_t *node)
{
if (node->right && !node->left)
{
if (node && node->right && node->right->right && node->level == node->right->right->level)
if (node->right->left && !node->right->right)
{
// Not allowed: two consecutive horizontal right-links.
// The middle one becomes the new root at this point,
// with suitable adjustments below.
node->right = M_AATreeRotateRight(node->right);
return M_AATreeRotateLeft(node);
}
aatree_node_t *oldright = node->right;
node->right = oldright->left;
oldright->left = node;
oldright->level++;
if (node->right->right && !node->right->left)
{
return M_AATreeRotateLeft(node);
}
}
else if (node->left && !node->right)
{
if (node->left->right && !node->left->left)
{
node->left = M_AATreeRotateLeft(node->left);
return M_AATreeRotateRight(node);
}
return oldright;
if (node->left->left && !node->left->right)
{
return M_AATreeRotateRight(node);
}
}
// No change needed.
return node;
}
static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, void* key, void* value, aatree_comp_t callback, aatree_dealloc_t deallocator)
{
if (!node)
{
// Nothing here, so just add where we are
node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
node->level = 1;
node->key = key;
if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
else node->value = value;
if (value && (flags & AATREE_ZUSER))
Z_SetUser(value, &node->value);
else
node->value = value;
node->left = node->right = NULL;
}
else
{
if (key < node->key)
node->left = M_AATreeSet_Node(node->left, flags, key, value);
else if (key > node->key)
node->right = M_AATreeSet_Node(node->right, flags, key, value);
if (callback(key, node->key) < 0)
node->left = M_AATreeSet_Node(node->left, flags, key, value, callback, deallocator);
else if (callback(key, node->key) > 0)
node->right = M_AATreeSet_Node(node->right, flags, key, value, callback, deallocator);
else
{
if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
else node->value = value;
if (value && (flags & AATREE_ZUSER))
Z_SetUser(value, &node->value);
else
node->value = value;
if (deallocator)
deallocator(key);
}
node = M_AATreeSkew(node);
node = M_AATreeSplit(node);
node = M_AATreeRebalance(node);
}
return node;
}
void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
void M_AATreeSet(aatree_t *aatree, void* key, void* value, aatree_comp_t callback, aatree_dealloc_t deallocator)
{
aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
I_Assert(callback != NULL);
aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value, callback, deallocator);
}
// Caveat: we don't distinguish between nodes that don't exists
// and nodes with value == NULL.
static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
static void *M_AATreeGet_Node(aatree_node_t *node, void* key, aatree_comp_t callback, aatree_dealloc_t deallocator)
{
if (node)
{
if (node->key == key)
if (callback(key, node->key) == 0)
{
if (deallocator)
deallocator(key);
return node->value;
else if(node->key < key)
return M_AATreeGet_Node(node->right, key);
}
else if(callback(node->key, key) < 0)
return M_AATreeGet_Node(node->right, key, callback, deallocator);
else
return M_AATreeGet_Node(node->left, key);
return M_AATreeGet_Node(node->left, key, callback, deallocator);
}
if (deallocator)
deallocator(key);
return NULL;
}
void *M_AATreeGet(aatree_t *aatree, INT32 key)
void *M_AATreeGet(aatree_t *aatree, void* key, aatree_comp_t callback, aatree_dealloc_t deallocator)
{
return M_AATreeGet_Node(aatree->root, key);
I_Assert(callback != NULL);
return M_AATreeGet_Node(aatree->root, key, callback, deallocator);
}
static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
{
if (node->left) M_AATreeIterate_Node(node->left, callback);
if (node->left)
M_AATreeIterate_Node(node->left, callback);
callback(node->key, node->value);
if (node->right) M_AATreeIterate_Node(node->right, callback);
if (node->right)
M_AATreeIterate_Node(node->right, callback);
}
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2025 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -20,12 +20,14 @@
#define AATREE_ZUSER 1 // Treat values as z_zone-allocated blocks and set their user fields
typedef struct aatree_s aatree_t;
typedef void (*aatree_iter_t)(INT32 key, void *value);
typedef void (*aatree_iter_t)(void* key, void *value);
typedef INT32 (*aatree_comp_t)(void* key, void *value);
typedef void (*aatree_dealloc_t)(void* key);
aatree_t *M_AATreeAlloc(UINT32 flags);
void M_AATreeFree(aatree_t *aatree);
void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
void *M_AATreeGet(aatree_t *aatree, INT32 key);
void M_AATreeSet(aatree_t *aatree, void* key, void* value, aatree_comp_t callback, aatree_dealloc_t deallocator);
void *M_AATreeGet(aatree_t *aatree, void* key, aatree_comp_t callback, aatree_dealloc_t deallocator);
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
#endif
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2013 by "Ninji".
// Copyright (C) 2013-2023 by Sonic Team Junior.
// Copyright (C) 2013-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -75,7 +75,7 @@ static UINT8 cheatf_warp(void)
if (menuactive && currentMenu != &MainDef)
return 0; // Only on the main menu!
S_StartSound(0, sfx_itemup);
S_StartSoundFromEverywhere(sfx_itemup);
// Temporarily unlock stuff.
G_SetUsedCheats(false);
......@@ -97,7 +97,7 @@ static UINT8 cheatf_devmode(void)
if (menuactive && currentMenu != &MainDef)
return 0; // Only on the main menu!
S_StartSound(0, sfx_itemup);
S_StartSoundFromEverywhere(sfx_itemup);
// Just unlock all the things and turn on -debug and console devmode.
G_SetUsedCheats(false);
......@@ -472,7 +472,7 @@ void Command_RTeleport_f(void)
if (!P_SetOrigin(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz))
CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n"));
else
S_StartSound(p->mo, sfx_mixup);
S_StartSoundFromMobj(p->mo, sfx_mixup);
P_MapEnd();
}
......@@ -562,7 +562,7 @@ void Command_Teleport_f(void)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -693,7 +693,7 @@ void Command_Teleport_f(void)
if (!P_SetOrigin(p->mo, intx, inty, intz))
CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n"));
else
S_StartSound(p->mo, sfx_mixup);
S_StartSoundFromMobj(p->mo, sfx_mixup);
P_MapEnd();
}
......@@ -1072,7 +1072,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo = (mobj_t *)th;
......@@ -1110,9 +1110,9 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
mt->pitch = mt->roll = 0;
// Ignore offsets
if (mt->type == MT_EMBLEM)
if (mt->type == mobjinfo[MT_EMBLEM].doomednum)
mt->args[1] = 1;
else
else if (!(mt->type == mobjinfo[MT_METALSONIC_RACE].doomednum || mt->type == mobjinfo[MT_ROSY].doomednum))
mt->args[0] = 1;
return mt;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2012-2023 by Sonic Team Junior.
// Copyright (C) 2012-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -155,6 +155,8 @@ void M_ClearSecrets(gamedata_t *data)
data->unlocked[i] = false;
for (i = 0; i < MAXCONDITIONSETS; ++i)
data->achieved[i] = false;
for (i = 0; i < MAXLUACONDITIONS; ++i)
data->lua[i] = false;
data->timesBeaten = data->timesBeatenWithEmeralds = data->timesBeatenUltimate = 0;
......@@ -214,6 +216,8 @@ static UINT8 M_CheckCondition(condition_t *cn, gamedata_t *data)
return data->collected[cn->requirement-1];
case UC_EXTRAEMBLEM: // Requires extra emblem x to be obtained
return data->extraCollected[cn->requirement-1];
case UC_LUA:
return data->lua[cn->requirement-1];
case UC_CONDITIONSET: // requires condition set x to already be achieved
return M_Achieved(cn->requirement-1, data);
}
......@@ -494,6 +498,12 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data)
{
if (dedicated)
{
// See M_MapLocked; don't make dedicated servers annoying.
return false;
}
if (M_MapLocked(mapnum, data) == true)
{
// Warping to locked maps is definitely always a cheat
......
......@@ -47,6 +47,7 @@ typedef enum
UC_EMBLEM, // EMBLEM [emblem number]
UC_EXTRAEMBLEM, // EXTRAEMBLEM [extra emblem number]
UC_CONDITIONSET, // CONDITIONSET [condition set number]
UC_LUA, // LUA [condition set number]
} conditiontype_t;
// Condition Set information
......@@ -141,6 +142,7 @@ typedef struct
#define MAXEMBLEMS 512
#define MAXEXTRAEMBLEMS 48
#define MAXUNLOCKABLES 80
#define MAXLUACONDITIONS 128
/** Time attack information, currently a very small structure.
*/
......@@ -202,6 +204,9 @@ typedef struct
// UNLOCKABLES UNLOCKED
boolean unlocked[MAXUNLOCKABLES];
// LUA DATA (NOT SAVED INTO GAMEDATA)
boolean lua[MAXLUACONDITIONS];
// TIME ATTACK DATA
recorddata_t *mainrecords[NUMMAPS];
nightsdata_t *nightsrecords[NUMMAPS];
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos.
// Copyright (C) 2020-2023 by Lactozilla.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos.
// Copyright (C) 2020-2023 by Lactozilla.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
// Copyright (C) 2009 by Stephen McGranahan.
//
// This program is free software distributed under the
......@@ -869,10 +869,10 @@ boolean FV3_PointInsideBox(const vector3_t *point, const vector3_t *box)
//
// Loads the identity matrix into a matrix
//
void FM_LoadIdentity(matrix_t* matrix)
void FM_LoadIdentity(oldmatrix_t* matrix)
{
#define M(row,col) matrix->m[col * 4 + row]
memset(matrix, 0x00, sizeof(matrix_t));
memset(matrix, 0x00, sizeof(oldmatrix_t));
M(0, 0) = FRACUNIT;
M(1, 1) = FRACUNIT;
......@@ -887,7 +887,7 @@ void FM_LoadIdentity(matrix_t* matrix)
// Creates a matrix that can be used for
// adjusting the position of an object
//
void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fixed_t anglex, fixed_t angley, fixed_t anglez, fixed_t upx, fixed_t upy, fixed_t upz, fixed_t radius)
void FM_CreateObjectMatrix(oldmatrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fixed_t anglex, fixed_t angley, fixed_t anglez, fixed_t upx, fixed_t upy, fixed_t upz, fixed_t radius)
{
vector3_t upcross;
vector3_t upvec;
......@@ -926,7 +926,7 @@ void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fi
//
// Multiplies a vector by the specified matrix
//
const vector3_t *FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out)
const vector3_t *FM_MultMatrixVec3(const oldmatrix_t *matrix, const vector3_t *vec, vector3_t *out)
{
#define M(row,col) matrix->m[col * 4 + row]
out->x = FixedMul(vec->x, M(0, 0))
......@@ -947,7 +947,7 @@ const vector3_t *FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec,
return out;
}
const vector4_t *FM_MultMatrixVec4(const matrix_t *matrix, const vector4_t *vec, vector4_t *out)
const vector4_t *FM_MultMatrixVec4(const oldmatrix_t *matrix, const vector4_t *vec, vector4_t *out)
{
#define M(row,col) matrix->m[col * 4 + row]
out->x = FixedMul(vec->x, M(0, 0))
......@@ -979,9 +979,9 @@ const vector4_t *FM_MultMatrixVec4(const matrix_t *matrix, const vector4_t *vec,
//
// Multiples one matrix into another
//
void FM_MultMatrix(matrix_t *dest, const matrix_t *multme)
void FM_MultMatrix(oldmatrix_t *dest, const oldmatrix_t *multme)
{
matrix_t result;
oldmatrix_t result;
UINT8 i, j;
#define M(row,col) multme->m[col * 4 + row]
#define D(row,col) dest->m[col * 4 + row]
......@@ -993,7 +993,7 @@ void FM_MultMatrix(matrix_t *dest, const matrix_t *multme)
R(i, j) = FixedMul(D(i, 0), M(0, j)) + FixedMul(D(i, 1), M(1, j)) + FixedMul(D(i, 2), M(2, j)) + FixedMul(D(i, 3), M(3, j));
}
M_Memcpy(dest, &result, sizeof(matrix_t));
M_Memcpy(dest, &result, sizeof(oldmatrix_t));
#undef R
#undef D
......@@ -1005,12 +1005,12 @@ void FM_MultMatrix(matrix_t *dest, const matrix_t *multme)
//
// Translates a matrix
//
void FM_Translate(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z)
void FM_Translate(oldmatrix_t *dest, fixed_t x, fixed_t y, fixed_t z)
{
matrix_t trans;
oldmatrix_t trans;
#define M(row,col) trans.m[col * 4 + row]
memset(&trans, 0x00, sizeof(matrix_t));
memset(&trans, 0x00, sizeof(oldmatrix_t));
M(0, 0) = M(1, 1) = M(2, 2) = M(3, 3) = FRACUNIT;
M(0, 3) = x;
......@@ -1026,12 +1026,12 @@ void FM_Translate(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z)
//
// Scales a matrix
//
void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z)
void FM_Scale(oldmatrix_t *dest, fixed_t x, fixed_t y, fixed_t z)
{
matrix_t scale;
oldmatrix_t scale;
#define M(row,col) scale.m[col * 4 + row]
memset(&scale, 0x00, sizeof(matrix_t));
memset(&scale, 0x00, sizeof(oldmatrix_t));
M(3, 3) = FRACUNIT;
M(0, 0) = x;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -347,14 +347,14 @@ fixed_t FV4_Dot(const vector4_t *a_1, const vector4_t *a_2);
typedef struct
{
fixed_t m[16];
} matrix_t;
void FM_LoadIdentity(matrix_t* matrix);
void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fixed_t anglex, fixed_t angley, fixed_t anglez, fixed_t upx, fixed_t upy, fixed_t upz, fixed_t radius);
const vector3_t *FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out);
const vector4_t *FM_MultMatrixVec4(const matrix_t *matrix, const vector4_t *vec, vector4_t *out);
void FM_MultMatrix(matrix_t *dest, const matrix_t *multme);
void FM_Translate(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
} oldmatrix_t;
void FM_LoadIdentity(oldmatrix_t* matrix);
void FM_CreateObjectMatrix(oldmatrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fixed_t anglex, fixed_t angley, fixed_t anglez, fixed_t upx, fixed_t upy, fixed_t upz, fixed_t radius);
const vector3_t *FM_MultMatrixVec3(const oldmatrix_t *matrix, const vector3_t *vec, vector3_t *out);
const vector4_t *FM_MultMatrixVec4(const oldmatrix_t *matrix, const vector4_t *vec, vector4_t *out);
void FM_MultMatrix(oldmatrix_t *dest, const oldmatrix_t *multme);
void FM_Translate(oldmatrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
void FM_Scale(oldmatrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
#endif //m_fixed.h
......@@ -3,7 +3,7 @@
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// 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
// terms of the GNU General Public License, version 2.
......@@ -48,6 +48,7 @@
#include "p_setup.h"
#include "f_finale.h"
#include "lua_hook.h"
#include "lua_libs.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
......@@ -123,9 +124,7 @@ typedef enum
NUM_QUITMESSAGES
} text_enum;
#ifdef HAVE_THREADS
I_mutex m_menu_mutex;
#endif
M_waiting_mode_t m_waiting_mode = M_NOT_WAITING;
......@@ -186,6 +185,7 @@ static tic_t keydown = 0;
// Lua
static huddrawlist_h luahuddrawlist_playersetup;
static huddrawlist_h luahuddrawlist_infoscreen;
//
// PROTOTYPES
......@@ -263,7 +263,7 @@ static void M_ConfirmTeamScramble(INT32 choice);
static void M_ConfirmTeamChange(INT32 choice);
static void M_SecretsMenu(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);
menu_t SP_MainDef, OP_MainDef;
menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef;
......@@ -316,6 +316,7 @@ menu_t OP_P1ControlsDef, OP_P2ControlsDef, OP_MouseOptionsDef;
menu_t OP_Mouse2OptionsDef, OP_Joystick1Def, OP_Joystick2Def;
menu_t OP_CameraOptionsDef, OP_Camera2OptionsDef;
menu_t OP_PlaystyleDef;
menu_t OP_AddonCustomOptionsDef;
static void M_VideoModeMenu(INT32 choice);
static void M_Setup1PControlsMenu(INT32 choice);
static void M_Setup2PControlsMenu(INT32 choice);
......@@ -349,6 +350,7 @@ static void M_EraseData(INT32 choice);
static void M_Addons(INT32 choice);
static void M_AddonsOptions(INT32 choice);
static void M_AddonsCvarOptions(INT32 choice);
static patch_t *addonsp[NUM_EXT+5];
#define addonmenusize 9 // number of items actually displayed in the addons menu view, formerly (2*numaddonsshown + 1)
......@@ -393,6 +395,7 @@ static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t colo
// Handling functions
static boolean M_ExitPandorasBox(void);
static boolean M_QuitMultiPlayerMenu(void);
static boolean M_QuitPauseMenu(void);
static void M_HandleAddons(INT32 choice);
static void M_HandleLevelPlatter(INT32 choice);
static void M_HandleSoundTest(INT32 choice);
......@@ -1037,6 +1040,7 @@ static menuitem_t OP_MainMenu[] =
{IT_CALL | IT_STRING, NULL, "Server Options...", M_ServerOptions, 80},
{IT_SUBMENU | IT_STRING, NULL, "Data Options...", &OP_DataOptionsDef, 100},
{IT_CALL | IT_STRING, NULL, "Custom Options...", M_AddonsCvarOptions,110},
};
static menuitem_t OP_P1ControlsMenu[] =
......@@ -1073,7 +1077,6 @@ static menuitem_t OP_ChangeControlsMenu[] =
{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, "Spin", M_ChangeControl, GC_SPIN },
{IT_CALL | IT_STRING2, NULL, "Shield Ability", M_ChangeControl, GC_SHIELD },
{IT_HEADER, NULL, "Camera", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Look Up", M_ChangeControl, GC_LOOKUP },
......@@ -1122,15 +1125,13 @@ static menuitem_t OP_ChangeControlsMenu[] =
static menuitem_t OP_Joystick1Menu[] =
{
{IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup1PJoystickMenu, 0},
{IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis , 20},
{IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis , 30},
{IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis , 40},
{IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis , 50},
{IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis , 60},
{IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis , 70},
{IT_STRING | IT_CVAR, NULL, "Shield Axis" , &cv_shieldaxis , 80},
{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 \x18 Axis" , &cv_sideaxis , 40},
{IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis , 50},
{IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis , 60},
{IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis , 70},
{IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis , 80},
{IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis , 90},
{IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis ,100},
......@@ -1142,15 +1143,13 @@ static menuitem_t OP_Joystick1Menu[] =
static menuitem_t OP_Joystick2Menu[] =
{
{IT_STRING | IT_CALL, NULL, "Select Gamepad...", M_Setup2PJoystickMenu, 0},
{IT_STRING | IT_CVAR, NULL, "Move \x17 Axis" , &cv_moveaxis2 , 20},
{IT_STRING | IT_CVAR, NULL, "Move \x18 Axis" , &cv_sideaxis2 , 30},
{IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis2 , 40},
{IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis2 , 50},
{IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis2 , 60},
{IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis2 , 70},
{IT_STRING | IT_CVAR, NULL, "Shield Axis" , &cv_shieldaxis2 , 80},
{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 \x18 Axis" , &cv_sideaxis2 , 40},
{IT_STRING | IT_CVAR, NULL, "Camera \x17 Axis" , &cv_lookaxis2 , 50},
{IT_STRING | IT_CVAR, NULL, "Camera \x18 Axis" , &cv_turnaxis2 , 60},
{IT_STRING | IT_CVAR, NULL, "Jump Axis" , &cv_jumpaxis2 , 70},
{IT_STRING | IT_CVAR, NULL, "Spin Axis" , &cv_spinaxis2 , 80},
{IT_STRING | IT_CVAR, NULL, "Fire Axis" , &cv_fireaxis2 , 90},
{IT_STRING | IT_CVAR, NULL, "Fire Normal Axis" , &cv_firenaxis2 ,100},
......@@ -1648,6 +1647,9 @@ static menuitem_t OP_MonitorToggleMenu[] =
{IT_STRING|IT_CVAR|IT_CV_INVISSLIDER, NULL, "Eggman Box", &cv_eggmanbox, 140},
};
#define MAXADDONOPTIONS 999
menuitem_t OP_AddonOptionsSlots[MAXADDONOPTIONS];
// ==========================================================================
// ALL MENU DEFINITIONS GO HERE
// ==========================================================================
......@@ -2102,6 +2104,12 @@ menu_t OP_PlaystyleDef = {
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)
{
(void)choice;
......@@ -2218,6 +2226,23 @@ menu_t OP_ScreenshotOptionsDef =
NULL
};
INT16 menu_cc_pos = 0;
static void M_AddonsCvarOptions(INT32 choice)
{
(void)choice;
if (menu_cc_pos)
M_SetupNextMenu(&OP_AddonCustomOptionsDef);
else
M_StartMessage(M_GetText("No Custom Option was found.\nTry to load any Addon!\n(Press a key)\n"), NULL, MM_NOTHING);
}
menu_t OP_AddonCustomOptionsDef = DEFAULTSCROLLMENUSTYLE(
MTREE3(MN_OP_MAIN, MN_OP_DATA, MN_OP_ADDONS),
"M_ADDONS", OP_AddonOptionsSlots, &OP_MainDef, 30, 30);
menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE(
MTREE3(MN_OP_MAIN, MN_OP_DATA, MN_OP_ADDONS),
"M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30);
......@@ -2329,6 +2354,7 @@ void Nextmap_OnChange(void)
{
currentMenu->lastOn = itemOn;
itemOn = nastart;
M_UpdateItemOn();
}
}
else if (currentMenu == &SP_TimeAttackDef)
......@@ -2378,6 +2404,7 @@ void Nextmap_OnChange(void)
{
currentMenu->lastOn = itemOn;
itemOn = tastart;
M_UpdateItemOn();
}
if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0')
......@@ -3128,6 +3155,7 @@ static void M_NextOpt(void)
else
itemOn++;
} while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE ));
M_UpdateItemOn();
}
static void M_PrevOpt(void)
......@@ -3140,6 +3168,7 @@ static void M_PrevOpt(void)
else
itemOn--;
} 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
......@@ -3306,7 +3335,7 @@ boolean M_Responder(event_t *ev)
if (ch == -1)
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;
// F-Keys
......@@ -3384,9 +3413,16 @@ boolean M_Responder(event_t *ev)
// Handle menuitems which need a specific key handling
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
// 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;
routine(ch);
......@@ -3414,7 +3450,7 @@ boolean M_Responder(event_t *ev)
{
// 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
|| ev->type == ev_joystick2)
|| ev->type == ev_joystick2 || ev->type == ev_text)
return true;
if (routine)
{
......@@ -3449,19 +3485,19 @@ boolean M_Responder(event_t *ev)
{
case KEY_DOWNARROW:
M_NextOpt();
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
return true;
case KEY_UPARROW:
M_PrevOpt();
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
return true;
case KEY_LEFTARROW:
if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS
|| (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR))
{
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
routine(0);
}
return true;
......@@ -3470,7 +3506,7 @@ boolean M_Responder(event_t *ev)
if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS
|| (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR))
{
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
routine(1);
}
return true;
......@@ -3489,13 +3525,13 @@ boolean M_Responder(event_t *ev)
// It'd be nice to get rid of this once and for all though!
if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && usedCheats)
{
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
M_StartMessage(M_GetText("This cannot be done in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING);
return true;
}
#endif
}
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
switch (currentMenu->menuitems[itemOn].status & IT_TYPE)
{
case IT_CVAR:
......@@ -3526,7 +3562,7 @@ boolean M_Responder(event_t *ev)
{
// detach any keys associated with the game control
G_ClearControlKeys(setupcontrols, currentMenu->menuitems[itemOn].alphaKey);
S_StartSound(NULL, sfx_shldls);
S_StartSoundFromEverywhere(sfx_shldls);
return true;
}
......@@ -3541,7 +3577,7 @@ boolean M_Responder(event_t *ev)
return true;
if (currentMenu != &OP_SoundOptionsDef || itemOn > 3)
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
routine(-1);
return true;
}
......@@ -3651,21 +3687,27 @@ void M_StartControlPanel(void)
currentMenu = &MainDef;
itemOn = singleplr;
M_UpdateItemOn();
}
else if (modeattacking)
{
currentMenu = &MAPauseDef;
MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
itemOn = mapause_continue;
M_UpdateItemOn();
}
else if (!(netgame || multiplayer)) // Single Player
{
// Devmode unlocks Pandora's Box in the pause menu
boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) || cv_debug || devparm) && !marathonmode);
// Devmode unlocks Pandora's Box and Level Select in the pause menu
boolean isforbidden = (marathonmode || ultimatemode);
boolean isdebug = ((cv_debug || devparm) && !isforbidden);
boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !isforbidden) || isdebug);
boolean lselect = ((maplistoption != 0 && !isforbidden) || isdebug);
if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff.
if (gamestate != GS_LEVEL) // intermission, so gray out stuff.
{
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;
}
else
......@@ -3675,6 +3717,11 @@ void M_StartControlPanel(void)
++numlives;
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
// for me to want to use the short if statement syntax
......@@ -3684,13 +3731,6 @@ void M_StartControlPanel(void)
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.
SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS, clientGamedata) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
......@@ -3703,6 +3743,7 @@ void M_StartControlPanel(void)
currentMenu = &SPauseDef;
itemOn = spause_continue;
M_UpdateItemOn();
}
else // multiplayer
{
......@@ -3744,11 +3785,20 @@ void M_StartControlPanel(void)
currentMenu = &MPauseDef;
itemOn = mpause_continue;
M_UpdateItemOn();
}
CON_ToggleOff(); // move away console
}
static boolean M_QuitPauseMenu(void)
{
LUA_HUD_DestroyDrawList(luahuddrawlist_infoscreen);
luahuddrawlist_infoscreen = NULL;
return true;
}
void M_EndModeAttackRun(void)
{
G_ClearModeAttackRetryFlag();
......@@ -3775,6 +3825,7 @@ void M_ClearMenus(boolean callexitmenufunc)
hidetitlemap = false;
I_UpdateMouseGrab();
I_SetTextInputMode(textinputmodeenabledbylua);
}
//
......@@ -3784,7 +3835,9 @@ void M_SetupNextMenu(menu_t *menudef)
{
INT16 i;
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
#if defined (MASTERSERVER)
if (I_can_thread())
{
if (currentMenu == &MP_RoomDef || currentMenu == &MP_ConnectDef)
{
I_lock_mutex(&ms_QueryId_mutex);
......@@ -3806,7 +3859,8 @@ void M_SetupNextMenu(menu_t *menudef)
}
I_unlock_mutex(ms_ServerList_mutex);
}
#endif/*HAVE_THREADS*/
}
#endif/*MASTERSERVER*/
if (currentMenu->quitroutine)
{
......@@ -3837,6 +3891,7 @@ void M_SetupNextMenu(menu_t *menudef)
}
}
}
M_UpdateItemOn();
hidetitlemap = false;
}
......@@ -3872,7 +3927,10 @@ void M_Ticker(void)
if (currentMenu == &OP_ScreenshotOptionsDef)
M_SetupScreenshotMenu();
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
#if defined (MASTERSERVER)
if (!netgame)
return;
I_lock_mutex(&ms_ServerList_mutex);
{
if (ms_ServerList)
......@@ -4015,11 +4073,11 @@ static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv)
lumpnum_t leftlump, rightlump, centerlump[2], cursorlump;
patch_t *p;
leftlump = W_GetNumForName("M_THERML");
rightlump = W_GetNumForName("M_THERMR");
centerlump[0] = W_GetNumForName("M_THERMM");
centerlump[1] = W_GetNumForName("M_THERMM");
cursorlump = W_GetNumForName("M_THERMO");
leftlump = W_GetNumForPatchName("M_THERML");
rightlump = W_GetNumForPatchName("M_THERMR");
centerlump[0] = W_GetNumForPatchName("M_THERMM");
centerlump[1] = W_GetNumForPatchName("M_THERMM");
cursorlump = W_GetNumForPatchName("M_THERMO");
V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_PATCH));
xx += p->width - p->leftoffset;
......@@ -4697,8 +4755,32 @@ static void M_DrawPauseMenu(void)
emblem_t *emblem_detail[3] = {NULL, NULL, NULL};
char emblem_text[3][20];
INT32 i;
INT16 xbox = 27;
INT16 ybox = 16;
INT16 widthbox = 32;
INT16 heightbox = 6;
M_DrawTextBox(xbox, ybox, widthbox, heightbox);
if (!LUA_HUD_IsDrawListValid(luahuddrawlist_infoscreen))
{
LUA_HUD_DestroyDrawList(luahuddrawlist_infoscreen);
luahuddrawlist_infoscreen = LUA_HUD_CreateDrawList();
}
LUA_HUD_ClearDrawList(luahuddrawlist_infoscreen);
boolean esc_override = LUA_HookEscapePanel(
HUD_HOOK(escpanel),
luahuddrawlist_infoscreen,
xbox+5, ybox+5, widthbox*8+6, heightbox*8+6);
M_DrawTextBox(27, 16, 32, 6);
LUA_HUD_DrawList(luahuddrawlist_infoscreen);
if (esc_override)
{
M_DrawGenericMenu();
return;
}
// Draw any and all emblems at the top.
M_DrawMapEmblems(gamemap, 272, 28, true);
......@@ -5496,7 +5578,7 @@ static void M_HandleLevelPlatter(INT32 choice)
if (!lsoffs[0]) // prevent sound spam
{
lsoffs[0] = -8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
}
return;
}
......@@ -5510,7 +5592,7 @@ static void M_HandleLevelPlatter(INT32 choice)
lshli = lsrow;
// no else needed - headerless lines associate upwards, so moving down to a row without a header is identity
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
break;
......@@ -5524,7 +5606,7 @@ static void M_HandleLevelPlatter(INT32 choice)
if (!lsoffs[0]) // prevent sound spam
{
lsoffs[0] = 8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
}
return;
}
......@@ -5545,7 +5627,7 @@ static void M_HandleLevelPlatter(INT32 choice)
lshli = iter;
}
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
break;
......@@ -5555,7 +5637,7 @@ static void M_HandleLevelPlatter(INT32 choice)
{
ifselectvalnextmapnobrace(lscol)
lsoffs[0] = lsoffs[1] = 0;
S_StartSound(NULL,sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (gamestate == GS_TIMEATTACK)
M_SetupNextMenu(currentMenu->prevMenu);
else if (currentMenu == &MISC_ChangeLevelDef)
......@@ -5574,7 +5656,7 @@ static void M_HandleLevelPlatter(INT32 choice)
else if (!lsoffs[0]) // prevent sound spam
{
lsoffs[0] = -8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb2);
S_StartSoundFromEverywhere(sfx_s3kb2);
}
break;
}
......@@ -5586,7 +5668,7 @@ static void M_HandleLevelPlatter(INT32 choice)
do
CV_AddValue(&cv_newgametype, 1);
while (cv_newgametype.value != startinggametype && !M_GametypeHasLevels(cv_newgametype.value));
S_StartSound(NULL,sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
lscol = 0;
Z_Free(char_notes);
......@@ -5600,14 +5682,14 @@ static void M_HandleLevelPlatter(INT32 choice)
lscol++;
lsoffs[1] = (lswide(lsrow) ? 8 : -lshseperation) * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
}
else if (!lsoffs[1]) // prevent sound spam
{
lsoffs[1] = 8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
}
break;
......@@ -5618,7 +5700,7 @@ static void M_HandleLevelPlatter(INT32 choice)
do
CV_AddValue(&cv_newgametype, -1);
while (cv_newgametype.value != startinggametype && !M_GametypeHasLevels(cv_newgametype.value));
S_StartSound(NULL,sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
lscol = 0;
Z_Free(char_notes);
......@@ -5632,14 +5714,14 @@ static void M_HandleLevelPlatter(INT32 choice)
lscol--;
lsoffs[1] = (lswide(lsrow) ? -8 : lshseperation) * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
}
else if (!lsoffs[1]) // prevent sound spam
{
lsoffs[1] = -8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
}
break;
......@@ -6109,6 +6191,7 @@ void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtyp
currentMenu = &MessageDef;
itemOn = 0;
M_UpdateItemOn();
}
static void M_DrawMessageMenu(void)
......@@ -6179,20 +6262,22 @@ static void M_HandleImageDef(INT32 choice)
if (currentMenu->numitems == 1)
break;
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (itemOn >= (INT16)(currentMenu->numitems-1))
itemOn = 0;
else itemOn++;
M_UpdateItemOn();
break;
case KEY_LEFTARROW:
if (currentMenu->numitems == 1)
break;
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (!itemOn)
itemOn = currentMenu->numitems - 1;
else itemOn--;
M_UpdateItemOn();
break;
case KEY_ESCAPE:
......@@ -6355,7 +6440,7 @@ static char *M_AddonsHeaderPath(void)
return header+len;
}
#define UNEXIST S_StartSound(NULL, sfx_lose);\
#define UNEXIST S_StartSoundFromEverywhere(sfx_lose);\
M_SetupNextMenu(MISC_AddonsDef.prevMenu);\
M_StartMessage(va("\x82%s\x80\nThis folder no longer exists!\nAborting to main menu.\n\n(Press a key)\n", M_AddonsHeaderPath()),NULL,MM_NOTHING)
......@@ -6383,7 +6468,7 @@ static boolean M_AddonsRefresh(void)
if (refreshdirmenu & REFRESHDIR_NOTLOADED)
{
S_StartSound(NULL, sfx_lose);
S_StartSoundFromEverywhere(sfx_lose);
if (refreshdirmenu & REFRESHDIR_MAX)
message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you wish to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
else
......@@ -6391,7 +6476,7 @@ static boolean M_AddonsRefresh(void)
}
else if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR))
{
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings"));
}
......@@ -6401,7 +6486,7 @@ static boolean M_AddonsRefresh(void)
return true;
}
S_StartSound(NULL, sfx_strpst);
S_StartSoundFromEverywhere(sfx_strpst);
CLEARNAME;
}
......@@ -6574,7 +6659,7 @@ static void M_AddonExec(INT32 ch)
if (ch != 'y' && ch != KEY_ENTER)
return;
S_StartSound(NULL, sfx_zoom);
S_StartSoundFromEverywhere(sfx_zoom);
COM_BufAddText(va("exec \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING));
}
......@@ -6643,14 +6728,14 @@ static void M_HandleAddons(INT32 choice)
dir_on[menudepthleft]++;
else if (dir_on[menudepthleft] == sizedirmenu-1)
dir_on[menudepthleft] = 0;
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
break;
case KEY_UPARROW:
if (dir_on[menudepthleft])
dir_on[menudepthleft]--;
else if (!dir_on[menudepthleft])
dir_on[menudepthleft] = sizedirmenu-1;
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
break;
case KEY_PGDN:
{
......@@ -6658,7 +6743,7 @@ static void M_HandleAddons(INT32 choice)
for (i = numaddonsshown; i && (dir_on[menudepthleft] < sizedirmenu-1); i--)
dir_on[menudepthleft]++;
}
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
break;
case KEY_PGUP:
{
......@@ -6666,13 +6751,13 @@ static void M_HandleAddons(INT32 choice)
for (i = numaddonsshown; i && (dir_on[menudepthleft]); i--)
dir_on[menudepthleft]--;
}
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
break;
case KEY_ENTER:
{
boolean refresh = true;
if (!dirmenu[dir_on[menudepthleft]])
S_StartSound(NULL, sfx_lose);
S_StartSoundFromEverywhere(sfx_lose);
else
{
switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE])
......@@ -6686,7 +6771,7 @@ static void M_HandleAddons(INT32 choice)
if (!preparefilemenu(false))
{
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING);
menupath[menupathindex[++menudepthleft]] = 0;
......@@ -6698,20 +6783,20 @@ static void M_HandleAddons(INT32 choice)
}
else
{
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
dir_on[menudepthleft] = 1;
}
refresh = false;
}
else
{
S_StartSound(NULL, sfx_lose);
S_StartSoundFromEverywhere(sfx_lose);
M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING);
menupath[menupathindex[menudepthleft]] = 0;
}
break;
case EXT_UP:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
menupath[menupathindex[++menudepthleft]] = 0;
if (!preparefilemenu(false))
{
......@@ -6735,7 +6820,7 @@ static void M_HandleAddons(INT32 choice)
COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING));
break;
default:
S_StartSound(NULL, sfx_lose);
S_StartSoundFromEverywhere(sfx_lose);
}
}
if (refresh)
......@@ -6915,6 +7000,65 @@ static void M_SelectableClearMenus(INT32 choice)
M_ClearMenus(true);
}
#define CCVHEIGHT 5
#define CCVHEIGHTHEADER 1
#define CCVHEIGHTHEADERAFTER 6
UINT16 menu_cc_lastoffset = 4;
INT16 menu_cc_lastheader = 0;
boolean CCSETUP = false;
void M_RegisterCustomCVOption(consvar_t* cvar)
{
if (menu_cc_pos == INT16_MAX)
return;
if (menu_cc_pos >= MAXADDONOPTIONS - 2)
{
CONS_Printf("Failed to register the console variable '%s' into the menu. Custom Options menu has reached its hard limit of %d.\n", cvar->displayname, MAXADDONOPTIONS);
menu_cc_pos = INT16_MAX;
return;
}
if (CCSETUP == false)
{
CONS_Printf("Custom Options menu initiation.\n");
for (INT16 i = 0; i < MAXADDONOPTIONS; ++i)
OP_AddonOptionsSlots[i] = (menuitem_t){ IT_DISABLED, NULL, "", 0, INT16_MAX };
CCSETUP = true;
}
if (
cvar->category && ((menu_cc_pos == 0 && cvar->category[0] != '\0')
|| !fasticmp(cvar->category, OP_AddonOptionsSlots[menu_cc_lastheader].text)))
{
menu_cc_lastheader = menu_cc_pos;
menu_cc_lastoffset += CCVHEIGHTHEADER;
OP_AddonOptionsSlots[menu_cc_pos] = (menuitem_t){ IT_HEADER, NULL, cvar->category, NULL, menu_cc_lastoffset };
menu_cc_lastoffset += CCVHEIGHTHEADERAFTER;
++menu_cc_pos;
}
UINT16 status = IT_STRING | IT_CVAR;
if (cvar->flags & CV_FLOAT)
status |= IT_CV_FLOATSLIDER;
else if (cvar->PossibleValue && cvar->PossibleValue[0].strvalue && fasticmp(cvar->PossibleValue[0].strvalue, "MIN"))
status |= IT_CV_SLIDER;
OP_AddonOptionsSlots[menu_cc_pos] = (menuitem_t){ status, NULL, cvar->displayname, cvar, menu_cc_lastoffset };
menu_cc_lastoffset += CCVHEIGHT;
++menu_cc_pos;
}
// ======
// CHEATS
// ======
......@@ -6982,7 +7126,10 @@ static void M_LevelSelectWarp(INT32 choice)
if (currentMenu == &SP_LevelSelectDef || currentMenu == &SP_PauseLevelSelectDef)
{
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
}
else // no save slot, start new game but keep the current skin
{
M_ClearMenus(true);
......@@ -7018,7 +7165,7 @@ static void M_HandleChecklist(INT32 choice)
switch (choice)
{
case KEY_DOWNARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if ((check_on != MAXUNLOCKABLES) && checklist_cangodown)
{
for (j = check_on+1; j < MAXUNLOCKABLES; j++)
......@@ -7043,7 +7190,7 @@ static void M_HandleChecklist(INT32 choice)
return;
case KEY_UPARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (check_on)
{
for (j = check_on-1; j > -1; j--)
......@@ -7389,6 +7536,7 @@ static void M_EmblemHints(INT32 choice)
SR_EmblemHintDef.prevMenu = currentMenu;
M_SetupNextMenu(&SR_EmblemHintDef);
itemOn = 2; // always start on back.
M_UpdateItemOn();
}
static void M_DrawEmblemHints(void)
......@@ -7521,13 +7669,9 @@ static void M_PauseLevelSelect(INT32 choice)
SP_PauseLevelSelectDef.prevMenu = currentMenu;
levellistmode = LLM_LEVELSELECT;
// maplistoption is only specified if not set already
// and we have the level select unlocked so that it
// maplistoption is NOT specified, so that this
// transfers the level select list from the 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))
{
M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING);
......@@ -7846,7 +7990,7 @@ static void M_HandleSoundTest(INT32 choice)
st_sel = 0;
{
cv_closedcaptioning.value = st_cc; // hack
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
cv_closedcaptioning.value = 1; // hack
}
break;
......@@ -7855,7 +7999,7 @@ static void M_HandleSoundTest(INT32 choice)
st_sel = numsoundtestdefs-1;
{
cv_closedcaptioning.value = st_cc; // hack
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
cv_closedcaptioning.value = 1; // hack
}
break;
......@@ -7866,7 +8010,7 @@ static void M_HandleSoundTest(INT32 choice)
if (st_sel >= numsoundtestdefs-1)
st_sel = numsoundtestdefs-1;
cv_closedcaptioning.value = st_cc; // hack
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
cv_closedcaptioning.value = 1; // hack
}
break;
......@@ -7877,7 +8021,7 @@ static void M_HandleSoundTest(INT32 choice)
if (st_sel < 0)
st_sel = 0;
cv_closedcaptioning.value = st_cc; // hack
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
cv_closedcaptioning.value = 1; // hack
}
break;
......@@ -7889,7 +8033,7 @@ static void M_HandleSoundTest(INT32 choice)
curplaying = NULL;
st_time = 0;
cv_closedcaptioning.value = st_cc; // hack
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
cv_closedcaptioning.value = 1; // hack
}
break;
......@@ -7928,7 +8072,7 @@ static void M_HandleSoundTest(INT32 choice)
{
// S_StopMusic() -- is this necessary?
if (cv_soundtest.value)
S_StartSound(NULL, cv_soundtest.value);
S_StartSoundFromEverywhere(cv_soundtest.value);
}
else
S_ChangeMusicInternal(curplaying->name, !curplaying->stoppingtics);
......@@ -7936,7 +8080,7 @@ static void M_HandleSoundTest(INT32 choice)
else
{
curplaying = NULL;
S_StartSound(NULL, sfx_lose);
S_StartSoundFromEverywhere(sfx_lose);
}
break;
......@@ -8187,10 +8331,10 @@ void M_TutorialSaveControlResponse(INT32 ch)
CV_Set(&cv_alwaysfreelook, cv_alwaysfreelook.defaultvalue);
CV_Set(&cv_mousemove, cv_mousemove.defaultvalue);
CV_Set(&cv_analog[0], cv_analog[0].defaultvalue);
S_StartSound(NULL, sfx_itemup);
S_StartSoundFromEverywhere(sfx_itemup);
}
else
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
}
static void M_TutorialControlResponse(INT32 ch)
......@@ -8212,17 +8356,17 @@ static void M_TutorialControlResponse(INT32 ch)
CV_Set(&cv_mousemove, cv_mousemove.defaultvalue);
CV_Set(&cv_analog[0], cv_analog[0].defaultvalue);
//S_StartSound(NULL, sfx_itemup);
//S_StartSoundFromEverywhere(sfx_itemup);
}
else
{
tutorialgcs = gcs_custom;
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
}
M_StartTutorial(INT32_MAX);
}
else
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
MessageDef.prevMenu = &SP_MainDef; // if FirstPrompt -> ControlsPrompt -> ESC, we would go to the main menu unless we force this
}
......@@ -8251,6 +8395,7 @@ static void M_StartTutorial(INT32 choice)
gamecomplete = 0;
cursaveslot = 0;
maplistoption = 0;
CV_StealthSet(&cv_skin, DEFAULTSKIN); // tutorial accounts for sonic only
G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false);
}
......@@ -8350,7 +8495,7 @@ static void M_DrawLoadGameData(void)
if (savegameinfo[savetodraw].lives == -42)
col = 26;
else if (savegameinfo[savetodraw].botskin == 3) // & knuckles
col = 105;
col = 106;
else if (savegameinfo[savetodraw].botskin) // tailsbot or custom
col = 134;
else
......@@ -8410,7 +8555,17 @@ static void M_DrawLoadGameData(void)
if (savegameinfo[savetodraw].lives == -42)
V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "NEW GAME");
else if (savegameinfo[savetodraw].lives == -666)
{
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)
V_DrawRightAlignedThinString(x + 79, y, V_GREENMAP, "CLEAR!");
else
......@@ -8630,14 +8785,20 @@ static void M_LoadSelect(INT32 choice)
M_NewGame();
}
else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed
{
M_LoadGameLevelSelect(0);
}
else
{
CV_StealthSet(&cv_skin, DEFAULTSKIN); // already handled by loadgame so we don't want this
G_LoadGame((UINT32)saveSlotSelected, 0);
}
cursaveslot = saveSlotSelected;
}
#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 CHECKPOS if (sav_p >= end_p) BADSAVE
// Reads the save file to list lives, level, player, etc.
......@@ -8734,10 +8895,11 @@ static void M_ReadSavegameInfo(UINT32 slot)
CHECKPOS
READSTRINGN(sav_p, ourSkinName, SKINNAMESIZE);
savegameinfo[slot].skinnum = R_SkinAvailable(ourSkinName);
STRBUFCPY(savegameinfo[slot].skinname, ourSkinName);
if (savegameinfo[slot].skinnum >= numskins
|| !R_SkinUsable(-1, savegameinfo[slot].skinnum))
BADSAVE
MISSING
CHECKPOS
READSTRINGN(sav_p, botSkinName, SKINNAMESIZE);
......@@ -8745,7 +8907,7 @@ static void M_ReadSavegameInfo(UINT32 slot)
if (savegameinfo[slot].botskin-1 >= numskins
|| !R_SkinUsable(-1, savegameinfo[slot].botskin-1))
BADSAVE
MISSING
}
CHECKPOS
......@@ -8790,6 +8952,7 @@ static void M_ReadSavegameInfo(UINT32 slot)
}
#undef CHECKPOS
#undef BADSAVE
#undef MISSING
//
// M_ReadSaveStrings
......@@ -8880,7 +9043,7 @@ static void M_SaveGameUltimateResponse(INT32 ch)
if (ch != 'y' && ch != KEY_ENTER)
return;
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
M_LoadSelect(saveSlotSelected);
SP_PlayerDef.prevMenu = MessageDef.prevMenu;
MessageDef.prevMenu = &SP_PlayerDef;
......@@ -8893,7 +9056,7 @@ static void M_HandleLoadSave(INT32 choice)
switch (choice)
{
case KEY_RIGHTARROW:
S_StartSound(NULL, sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
++saveSlotSelected;
if (saveSlotSelected >= numsaves)
saveSlotSelected -= numsaves;
......@@ -8901,7 +9064,7 @@ static void M_HandleLoadSave(INT32 choice)
break;
case KEY_LEFTARROW:
S_StartSound(NULL, sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
--saveSlotSelected;
if (saveSlotSelected < 0)
saveSlotSelected += numsaves;
......@@ -8912,24 +9075,24 @@ static void M_HandleLoadSave(INT32 choice)
if (ultimate_selectable && saveSlotSelected == NOSAVESLOT && !savemoddata)
{
loadgamescroll = 0;
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
M_StartMessage("Are you sure you want to play\n\x85ultimate mode\x80? It isn't remotely fair,\nand you don't even get an emblem for it.\n\n(Press 'Y' to confirm)\n",M_SaveGameUltimateResponse,MM_YESNO);
}
else if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected-1].lives == -42 && usedCheats)
{
loadgamescroll = 0;
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
M_StartMessage(M_GetText("This cannot be done in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING);
}
else if (saveSlotSelected == NOSAVESLOT || savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves"
{
loadgamescroll = 0;
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
M_LoadSelect(saveSlotSelected);
}
else if (!loadgameoffset)
{
S_StartSound(NULL, sfx_lose);
S_StartSoundFromEverywhere(sfx_lose);
loadgameoffset = 14 * FRACUNIT;
}
break;
......@@ -8944,7 +9107,7 @@ static void M_HandleLoadSave(INT32 choice)
if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected-1].lives != -42)
{
loadgamescroll = 0;
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
M_StartMessage(va("Are you sure you want to delete\nsave file %d?\n\n(Press 'Y' to confirm)\n", saveSlotSelected),M_SaveGameDeleteResponse,MM_YESNO);
}
else if (!loadgameoffset)
......@@ -8952,10 +9115,10 @@ static void M_HandleLoadSave(INT32 choice)
if (saveSlotSelected == NOSAVESLOT && ultimate_selectable)
{
ultimate_selectable = false;
S_StartSound(NULL, sfx_strpst);
S_StartSoundFromEverywhere(sfx_strpst);
}
else
S_StartSound(NULL, sfx_lose);
S_StartSoundFromEverywhere(sfx_lose);
loadgameoffset = 14 * FRACUNIT;
}
break;
......@@ -8975,7 +9138,7 @@ static void M_HandleLoadSave(INT32 choice)
static void M_FirstTimeResponse(INT32 ch)
{
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (ch == KEY_ESCAPE)
return;
......@@ -9053,7 +9216,7 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum)
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;
UINT16 i;
......@@ -9142,7 +9305,7 @@ static UINT16 M_SetupChoosePlayerDirect(INT32 choice)
static void M_SetupChoosePlayer(INT32 choice)
{
UINT16 skinset = M_SetupChoosePlayerDirect(choice);
INT32 skinset = M_SetupChoosePlayerDirect(choice);
if (skinset != MAXCHARACTERSLOTS)
{
M_ChoosePlayer(skinset);
......@@ -9190,7 +9353,7 @@ static void M_HandleChoosePlayerMenu(INT32 choice)
case KEY_DOWNARROW:
if ((selectval = description[char_on].next) != char_on)
{
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
char_on = selectval;
char_scroll = -charscrollamt;
Z_Free(char_notes);
......@@ -9198,7 +9361,7 @@ static void M_HandleChoosePlayerMenu(INT32 choice)
}
else if (!char_scroll)
{
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
char_scroll = 16*FRACUNIT;
}
break;
......@@ -9206,7 +9369,7 @@ static void M_HandleChoosePlayerMenu(INT32 choice)
case KEY_UPARROW:
if ((selectval = description[char_on].prev) != char_on)
{
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
char_on = selectval;
char_scroll = charscrollamt;
Z_Free(char_notes);
......@@ -9214,13 +9377,13 @@ static void M_HandleChoosePlayerMenu(INT32 choice)
}
else if (!char_scroll)
{
S_StartSound(NULL,sfx_s3kb7);
S_StartSoundFromEverywhere(sfx_s3kb7);
char_scroll = -16*FRACUNIT;
}
break;
case KEY_ENTER:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
char_scroll = 0; // finish scrolling the menu
M_DrawSetupChoosePlayerMenu(); // draw the finally selected character one last time for the fadeout
// Is this a hack?
......@@ -9491,6 +9654,8 @@ static void M_ChoosePlayer(INT32 choice)
//lastmapsaved = 0;
gamecomplete = 0;
CV_StealthSet(&cv_skin, skins[skinnum]->name);
G_DeferedInitNew(ultmode, G_BuildMapName(startmap), skinnum, false, fromlevelselect);
COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this
......@@ -9721,24 +9886,24 @@ static void M_HandleLevelStats(INT32 choice)
switch (choice)
{
case KEY_DOWNARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (statsLocation < statsMax)
++statsLocation;
break;
case KEY_UPARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (statsLocation)
--statsLocation;
break;
case KEY_PGDN:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
statsLocation += (statsLocation+13 >= statsMax) ? statsMax-statsLocation : 13;
break;
case KEY_PGUP:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
statsLocation -= (statsLocation < 13) ? statsLocation : 13;
break;
......@@ -10015,7 +10180,7 @@ static void M_HandleTimeAttackLevelSelect(INT32 choice)
default:
return;
}
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
}
static void M_TimeAttackLevelSelect(INT32 choice)
......@@ -10050,6 +10215,7 @@ static void M_TimeAttack(INT32 choice)
Nextmap_OnChange();
itemOn = tastart; // "Start" is selected.
M_UpdateItemOn();
}
// Drawing function for Nights Attack
......@@ -10181,9 +10347,12 @@ void M_DrawNightsAttackMenu(void)
color = skins[skinnumber]->prefcolor;
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),
FixedDiv(skins[skinnumber]->highresscale, skins[skinnumber]->shieldscale),
scale,
(sprframe->flip & 1<<6) ? V_FLIP : 0,
natksprite,
R_GetTranslationColormap(TC_BLINK, color, GTC_CACHE));
......@@ -10288,6 +10457,7 @@ static void M_NightsAttack(INT32 choice)
Nextmap_OnChange();
itemOn = nastart; // "Start" is selected.
M_UpdateItemOn();
}
// Player has selected the "START" from the nights attack screen
......@@ -10430,7 +10600,7 @@ static void M_ReplayTimeAttack(INT32 choice)
if (error)
{
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
switch (error)
{
......@@ -10607,6 +10777,7 @@ static void M_ModeAttackEndGame(INT32 choice)
break;
}
itemOn = currentMenu->lastOn;
M_UpdateItemOn();
G_SetGamestate(GS_TIMEATTACK);
modeattacking = ATTACKING_NONE;
M_ChangeMenuMusic("_title", true);
......@@ -10688,6 +10859,7 @@ static void M_Marathon(INT32 choice)
titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
M_SetupNextMenu(&SP_MarathonDef);
itemOn = marathonstart; // "Start" is selected.
M_UpdateItemOn();
recatkdrawtimer = (50-8) * FRACUNIT;
char_scroll = 0;
}
......@@ -10727,7 +10899,7 @@ static void M_HandleMarathonChoosePlayer(INT32 choice)
default:
return;
}
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
}
static void M_StartMarathon(INT32 choice)
......@@ -11020,11 +11192,11 @@ static void M_HandleServerPage(INT32 choice)
{
case KEY_DOWNARROW:
M_NextOpt();
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
break;
case KEY_UPARROW:
M_PrevOpt();
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
break;
case KEY_BACKSPACE:
case KEY_ESCAPE:
......@@ -11033,12 +11205,12 @@ static void M_HandleServerPage(INT32 choice)
case KEY_ENTER:
case KEY_RIGHTARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if ((serverlistpage + 1) * SERVERS_PER_PAGE < serverlistcount)
serverlistpage++;
break;
case KEY_LEFTARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (serverlistpage > 0)
serverlistpage--;
break;
......@@ -11078,7 +11250,7 @@ static void M_Refresh(INT32 choice)
// note: this is the one case where 0 is a valid room number
// 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
serverlistpage = 0;
......@@ -11088,37 +11260,11 @@ static INT32 menuRoomIndex = 0;
static void M_DrawRoomMenu(void)
{
static fixed_t frame = -(12 << FRACBITS);
int dot_frame;
char text[4];
const char *rmotd;
const char *waiting_message;
int dots;
if (m_waiting_mode)
{
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;
}
currentMenu->menuitems[0].text = "...";
// use generic drawer for cursor, items and title
M_DrawGenericMenu();
......@@ -11164,7 +11310,7 @@ static void M_DrawConnectMenu(void)
numPages = 1;
// 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_YELLOWMAP, (itemOn == mp_connect_room) ? "<Select to change>" : "<Unlisted Mode>");
else
......@@ -11325,7 +11471,7 @@ static boolean M_CheckMODVersion(int id)
}
#endif/*UPDATE_ALERT*/
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
#if defined (MASTERSERVER)
static void
Check_new_version_thread (int *id)
{
......@@ -11382,7 +11528,7 @@ Check_new_version_thread (int *id)
free(id);
}
#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/
#endif/*defined (MASTERSERVER)*/
static void M_ConnectMenu(INT32 choice)
{
......@@ -11392,7 +11538,7 @@ static void M_ConnectMenu(INT32 choice)
// first page of servers
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
// This prevents us from returning to the modified game alert.
......@@ -11401,6 +11547,7 @@ static void M_ConnectMenu(INT32 choice)
else
M_SetupNextMenu(&MP_ConnectDef);
itemOn = 0;
M_UpdateItemOn();
M_Refresh(0);
}
......@@ -11423,7 +11570,7 @@ UINT32 roomIds[NUM_LIST_ROOMS];
static void M_RoomMenu(INT32 choice)
{
INT32 i;
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
#if defined (MASTERSERVER)
int *id;
#endif
......@@ -11446,7 +11593,8 @@ static void M_RoomMenu(INT32 choice)
M_SetupNextMenu(&MP_RoomDef);
#ifdef MASTERSERVER
#ifdef HAVE_THREADS
if (I_can_thread())
{
#ifdef UPDATE_ALERT
m_waiting_mode = M_WAITING_VERSION;
#else/*UPDATE_ALERT*/
......@@ -11463,34 +11611,42 @@ static void M_RoomMenu(INT32 choice)
}
I_unlock_mutex(ms_QueryId_mutex);
I_spawn_thread("check-new-version",
(I_thread_fn)Check_new_version_thread, id);
#else/*HAVE_THREADS*/
if(!I_spawn_thread("check-new-version",
(I_thread_fn)Check_new_version_thread, id))
{
free(id);
}
}
else
{
#ifdef UPDATE_ALERT
if (M_CheckMODVersion(0))
#endif/*UPDATE_ALERT*/
{
GetRoomsList(currentMenu->prevMenu == &MP_ServerDef, 0);
}
#endif/*HAVE_THREADS*/
}
#endif/*MASTERSERVER*/
}
static void M_ChooseRoom(INT32 choice)
{
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
#if defined (MASTERSERVER)
if (I_can_thread())
{
I_lock_mutex(&ms_QueryId_mutex);
{
ms_QueryId++;
}
I_unlock_mutex(ms_QueryId_mutex);
}
#endif
if (choice == 0)
ms_RoomId = -1;
CV_SetValue(&cv_masterserver_room_id, -1);
else
{
ms_RoomId = roomIds[choice-1];
CV_SetValue(&cv_masterserver_room_id, roomIds[choice-1]);
menuRoomIndex = choice - 1;
}
......@@ -11559,7 +11715,7 @@ static void M_DrawServerMenu(void)
if (currentMenu == &MP_ServerDef)
{
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_YELLOWMAP, (itemOn == mp_server_room) ? "<Select to change>" : "<Unlisted Mode>");
else
......@@ -11655,11 +11811,12 @@ static void M_ServerOptions(INT32 choice)
static void M_StartServerMenu(INT32 choice)
{
(void)choice;
ms_RoomId = -1;
CV_SetValue(&cv_masterserver_room_id, -1);
levellistmode = LLM_CREATESERVER;
Newgametype_OnChange();
M_SetupNextMenu(&MP_ServerDef);
itemOn = 1;
M_UpdateItemOn();
}
// ==============
......@@ -11786,16 +11943,16 @@ static void M_HandleConnectIP(INT32 choice)
{
case KEY_DOWNARROW:
M_NextOpt();
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
break;
case KEY_UPARROW:
M_PrevOpt();
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
break;
case KEY_ENTER:
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
M_ConnectIP(1);
break;
......@@ -11806,7 +11963,7 @@ static void M_HandleConnectIP(INT32 choice)
case KEY_BACKSPACE:
if ((l = strlen(setupm_ip)) != 0)
{
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
setupm_ip[l-1] = 0;
}
break;
......@@ -11814,7 +11971,7 @@ static void M_HandleConnectIP(INT32 choice)
case KEY_DEL:
if (setupm_ip[0] && !shiftdown) // Shift+Delete is used for something else.
{
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
setupm_ip[0] = 0;
}
if (!shiftdown) // Shift+Delete is used for something else.
......@@ -11826,31 +11983,34 @@ static void M_HandleConnectIP(INT32 choice)
if ( ctrldown ) {
switch (choice) {
case 'v':
case 'V': // ctrl+v, pasting
case 'v': // ctrl+v, pasting
{
const char *paste = I_ClipboardPaste();
if (paste != NULL) {
strncat(setupm_ip, paste, CONNIP_LEN-1 - l); // Concat the ip field with clipboard
if (strlen(paste) != 0) // Don't play sound if nothing was pasted
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
}
break;
}
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
S_StartSoundFromEverywhere(sfx_menu1); // Tails
}
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
S_StartSoundFromEverywhere(sfx_menu1); // Tails
setupm_ip[0] = 0;
}
break;
default: // otherwise do nothing
......@@ -11868,15 +12028,18 @@ static void M_HandleConnectIP(INT32 choice)
if (paste != NULL) {
strncat(setupm_ip, paste, CONNIP_LEN-1 - l); // Concat the ip field with clipboard
if (strlen(paste) != 0) // Don't play sound if nothing was pasted
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
}
break;
}
case KEY_DEL: // shift+delete, cutting
if (l != 0) // Don't replace the clipboard without any text
{
I_ClipboardCopy(setupm_ip, l);
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
setupm_ip[0] = 0;
}
break;
default: // otherwise do nothing.
break;
......@@ -11893,19 +12056,10 @@ static void M_HandleConnectIP(INT32 choice)
(choice >= 'A' && choice <= 'Z') ||
(choice >= 'a' && choice <= 'z'))
{
S_StartSound(NULL,sfx_menu1); // Tails
setupm_ip[l] = (char)choice;
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
S_StartSoundFromEverywhere(sfx_menu1); // Tails
setupm_ip[l] = (char)choice;
setupm_ip[l+1] = 0;
}
break;
}
......@@ -12256,7 +12410,9 @@ static void M_DrawSetupMultiPlayerMenu(void)
if (multi_frame >= sprdef->numframes)
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)
......@@ -12289,7 +12445,7 @@ static void M_DrawSetupMultiPlayerMenu(void)
V_DrawFixedPatch(
x<<FRACBITS,
chary<<FRACBITS,
FixedDiv(skins[setupm_fakeskin]->highresscale, skins[setupm_fakeskin]->shieldscale),
scale,
flags, patch, colormap);
goto colordraw;
......@@ -12519,14 +12675,14 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
else
M_NextOpt();
S_StartSound(NULL,sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
}
break;
case KEY_LEFTARROW:
if (itemOn == 1) //player skin
{
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
prev_setupm_fakeskin = setupm_fakeskin;
do
{
......@@ -12541,7 +12697,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
else if (itemOn == 2) // player color
{
setupm_fakecolor = setupm_fakecolor->prev;
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
}
break;
......@@ -12550,7 +12706,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
&& (R_SkinAvailable(setupm_cvdefaultskin->string) != setupm_fakeskin
|| setupm_cvdefaultcolor->value != setupm_fakecolor->color))
{
S_StartSound(NULL,sfx_strpst);
S_StartSoundFromEverywhere(sfx_strpst);
// you know what? always putting these in the buffer won't hurt anything.
COM_BufAddText (va("%s \"%s\"\n",setupm_cvdefaultskin->name,skins[setupm_fakeskin]->name));
COM_BufAddText (va("%s %d\n",setupm_cvdefaultcolor->name,setupm_fakecolor->color));
......@@ -12559,7 +12715,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
else if (itemOn == 2)
{
if (!colorgrid)
S_StartSound(NULL,sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
colorgrid = !colorgrid;
break;
}
......@@ -12567,7 +12723,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
case KEY_RIGHTARROW:
if (itemOn == 1) //player skin
{
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
prev_setupm_fakeskin = setupm_fakeskin;
do
{
......@@ -12582,7 +12738,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
else if (itemOn == 2) // player color
{
setupm_fakecolor = setupm_fakecolor->next;
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
}
break;
......@@ -12613,7 +12769,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
}
}
S_StartSound(NULL, sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
}
}
break;
......@@ -12628,7 +12784,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
case KEY_BACKSPACE:
if (itemOn == 0 && (l = strlen(setupm_name))!=0)
{
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
setupm_name[l-1] = 0;
}
else if (itemOn == 2)
......@@ -12636,7 +12792,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
UINT16 col = skins[setupm_fakeskin]->prefcolor;
if ((setupm_fakecolor->color != col) && skincolors[col].accessible)
{
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
for (setupm_fakecolor=menucolorhead;;setupm_fakecolor=setupm_fakecolor->next)
if (setupm_fakecolor->color == col || setupm_fakecolor == menucolortail)
break;
......@@ -12647,7 +12803,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
case KEY_DEL:
if (itemOn == 0 && (l = strlen(setupm_name))!=0)
{
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
setupm_name[0] = 0;
}
break;
......@@ -12663,7 +12819,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
default:
if (itemOn != 0 || choice < 32 || choice > 127)
break;
S_StartSound(NULL,sfx_menu1); // Tails
S_StartSoundFromEverywhere(sfx_menu1); // Tails
l = strlen(setupm_name);
if (l < MAXPLAYERNAME)
{
......@@ -13071,7 +13227,10 @@ static void M_SetupScreenshotMenu(void)
{
item->status = IT_GRAYEDOUT;
if ((currentMenu == &OP_ScreenshotOptionsDef) && (itemOn == op_screenshot_colorprofile)) // Can't select that
{
itemOn = op_screenshot_storagelocation;
M_UpdateItemOn();
}
}
else
#endif
......@@ -13269,23 +13428,23 @@ static void M_Setup1PControlsMenu(INT32 choice)
currentMenu->lastOn = itemOn;
// Unhide the nine non-P2 controls and their headers
//OP_ChangeControlsMenu[19+0].status = IT_HEADER;
//OP_ChangeControlsMenu[19+1].status = IT_SPACE;
//OP_ChangeControlsMenu[18+0].status = IT_HEADER;
//OP_ChangeControlsMenu[18+1].status = IT_SPACE;
// ...
OP_ChangeControlsMenu[19+2].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+3].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+4].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+5].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+6].status = IT_CALL|IT_STRING2;
//OP_ChangeControlsMenu[19+7].status = IT_CALL|IT_STRING2;
//OP_ChangeControlsMenu[19+8].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[19+9].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[18+2].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[18+3].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[18+4].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[18+5].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[18+6].status = IT_CALL|IT_STRING2;
//OP_ChangeControlsMenu[18+7].status = IT_CALL|IT_STRING2;
//OP_ChangeControlsMenu[18+8].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[18+9].status = IT_CALL|IT_STRING2;
// ...
OP_ChangeControlsMenu[29+0].status = IT_HEADER;
OP_ChangeControlsMenu[29+1].status = IT_SPACE;
OP_ChangeControlsMenu[28+0].status = IT_HEADER;
OP_ChangeControlsMenu[28+1].status = IT_SPACE;
// ...
OP_ChangeControlsMenu[29+2].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[29+3].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[28+2].status = IT_CALL|IT_STRING2;
OP_ChangeControlsMenu[28+3].status = IT_CALL|IT_STRING2;
OP_ChangeControlsDef.prevMenu = &OP_P1ControlsDef;
OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level
......@@ -13301,23 +13460,23 @@ static void M_Setup2PControlsMenu(INT32 choice)
currentMenu->lastOn = itemOn;
// Hide the nine non-P2 controls and their headers
//OP_ChangeControlsMenu[19+0].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[19+1].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[18+0].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[18+1].status = IT_GRAYEDOUT2;
// ...
OP_ChangeControlsMenu[19+2].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+3].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+4].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+5].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+6].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[19+7].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[19+8].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[19+9].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[18+2].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[18+3].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[18+4].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[18+5].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[18+6].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[18+7].status = IT_GRAYEDOUT2;
//OP_ChangeControlsMenu[18+8].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[18+9].status = IT_GRAYEDOUT2;
// ...
OP_ChangeControlsMenu[29+0].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[29+1].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[28+0].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[28+1].status = IT_GRAYEDOUT2;
// ...
OP_ChangeControlsMenu[29+2].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[29+3].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[28+2].status = IT_GRAYEDOUT2;
OP_ChangeControlsMenu[28+3].status = IT_GRAYEDOUT2;
OP_ChangeControlsDef.prevMenu = &OP_P2ControlsDef;
OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove second level
......@@ -13515,7 +13674,7 @@ static void M_ChangecontrolResponse(event_t *ev)
(void)G_CheckDoubleUsage(ch, true);
setupcontrols[control][found] = ch;
}
S_StartSound(NULL, sfx_strpst);
S_StartSoundFromEverywhere(sfx_strpst);
}
else if (ch == KEY_PAUSE)
{
......@@ -13533,11 +13692,11 @@ static void M_ChangecontrolResponse(event_t *ev)
M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER);
currentMenu->prevMenu = prev;
S_StartSound(NULL, sfx_s3k42);
S_StartSoundFromEverywhere(sfx_s3k42);
return;
}
else
S_StartSound(NULL, sfx_skid);
S_StartSoundFromEverywhere(sfx_skid);
M_StopMessage(0);
}
......@@ -13605,7 +13764,7 @@ static void M_HandlePlaystyleMenu(INT32 choice)
break;
case KEY_ENTER:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
CV_SetValue((playstyle_activeplayer ? &cv_directionchar[1] : &cv_directionchar[0]), playstyle_currentchoice ? 1 : 0);
CV_SetValue((playstyle_activeplayer ? &cv_useranalog[1] : &cv_useranalog[0]), playstyle_currentchoice/2);
......@@ -13618,12 +13777,12 @@ static void M_HandlePlaystyleMenu(INT32 choice)
break;
case KEY_LEFTARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
playstyle_currentchoice = (playstyle_currentchoice+2)%3;
break;
case KEY_RIGHTARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
playstyle_currentchoice = (playstyle_currentchoice+1)%3;
break;
}
......@@ -13955,26 +14114,26 @@ static void M_HandleVideoMode(INT32 ch)
break;
case KEY_ENTER:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
vidm_testingmode = 0; // stop testing
}
else switch (ch)
{
case KEY_DOWNARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (++vidm_selected >= vidm_nummodes)
vidm_selected = 0;
break;
case KEY_UPARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
if (--vidm_selected < 0)
vidm_selected = vidm_nummodes - 1;
break;
case KEY_LEFTARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
vidm_selected -= vidm_column_size;
if (vidm_selected < 0)
vidm_selected = (vidm_column_size*3) + vidm_selected;
......@@ -13983,7 +14142,7 @@ static void M_HandleVideoMode(INT32 ch)
break;
case KEY_RIGHTARROW:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
vidm_selected += vidm_column_size;
if (vidm_selected >= (vidm_column_size*3))
vidm_selected %= vidm_column_size;
......@@ -13994,12 +14153,12 @@ static void M_HandleVideoMode(INT32 ch)
case KEY_ENTER:
if (vid.modenum == modedescs[vidm_selected].modenum)
{
S_StartSound(NULL, sfx_strpst);
S_StartSoundFromEverywhere(sfx_strpst);
SCR_SetDefaultMode();
}
else
{
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
vidm_testingmode = 15*TICRATE;
vidm_previousmode = vid.modenum;
if (!setmodeneeded) // in case the previous setmode was not finished
......@@ -14015,7 +14174,7 @@ static void M_HandleVideoMode(INT32 ch)
break;
case KEY_BACKSPACE:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
CV_Set(&cv_scr_width, cv_scr_width.defaultvalue);
CV_Set(&cv_scr_height, cv_scr_height.defaultvalue);
CV_Set(&cv_scr_width_w, cv_scr_width_w.defaultvalue);
......@@ -14031,7 +14190,7 @@ static void M_HandleVideoMode(INT32 ch)
break;
case KEY_F11:
S_StartSound(NULL, sfx_menu1);
S_StartSoundFromEverywhere(sfx_menu1);
CV_SetValue(&cv_fullscreen, !cv_fullscreen.value);
break;
......@@ -14118,6 +14277,33 @@ static INT32 quitsounds[] =
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)
{
tic_t ptime;
......@@ -14132,13 +14318,16 @@ void M_QuitResponse(INT32 ch)
marathonmode = 0;
mrand = M_RandomKey(sizeof(quitsounds)/sizeof(INT32));
if (quitsounds[mrand]) S_StartSound(NULL, quitsounds[mrand]);
if (quitsounds[mrand]) S_StartSoundFromEverywhere(quitsounds[mrand]);
//added : 12-02-98: do that instead of I_WaitVbl which does not work
ptime = I_GetTime() + NEWTICRATE*2; // Shortened the quit time, used to be 2 seconds Tails 03-26-2001
while (ptime > I_GetTime())
{
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_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
......
......@@ -3,7 +3,7 @@
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// 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
// terms of the GNU General Public License, version 2.
......@@ -143,7 +143,7 @@ typedef enum
typedef struct
{
char bgname[8]; // name for background gfx lump; lays over titlemap if this is set
char bgname[8+1]; // name for background gfx lump; lays over titlemap if this is set
SINT8 fadestrength; // darken background when displaying this menu, strength 0-31 or -1 for undefined
INT32 bgcolor; // fill color, overrides bg name. -1 means follow bg name rules.
INT32 titlescrollxspeed; // background gfx scroll per menu; inherits global setting
......@@ -153,13 +153,13 @@ typedef struct
SINT8 hidetitlepics; // hide title gfx per menu; -1 means undefined, inherits global setting
ttmode_enum ttmode; // title wing animation mode; default TTMODE_OLD
UINT8 ttscale; // scale of title wing gfx (FRACUNIT / ttscale); -1 means undefined, inherits global setting
char ttname[9]; // lump name of title wing gfx. If name length is <= 6, engine will attempt to load numbered frames (TTNAMExx)
char ttname[8+1]; // lump name of title wing gfx. If name length is <= 6, engine will attempt to load numbered frames (TTNAMExx)
INT16 ttx; // X position of title wing
INT16 tty; // Y position of title wing
INT16 ttloop; // # frame to loop; -1 means dont loop
UINT16 tttics; // # of tics per frame
char musname[7]; ///< Music track to play. "" for no music.
char musname[6+1]; ///< Music track to play. "" for no music.
UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
boolean muslooping; ///< Loop the music
boolean musstop; ///< Don't play any music
......@@ -352,9 +352,7 @@ void M_ClearMenus(boolean callexitmenufunc);
// Maybe this goes here????? Who knows.
boolean M_MouseNeeded(void);
#ifdef HAVE_THREADS
extern I_mutex m_menu_mutex;
#endif
extern menu_t *currentMenu;
......@@ -369,8 +367,8 @@ extern menu_t OP_JoystickSetDef;
typedef struct
{
boolean used;
char notes[441];
char picname[8];
char notes[440+1];
char picname[8+1];
char skinname[SKINNAMESIZE*2+2]; // skin&skin\0
patch_t *charpic;
UINT8 prev;
......@@ -421,6 +419,7 @@ typedef struct
{
char levelname[32];
UINT8 skinnum;
char skinname [SKINNAMESIZE+1];
UINT8 botskin;
UINT8 numemeralds;
UINT8 numgameovers;
......@@ -444,7 +443,7 @@ extern INT16 char_on, startchar;
#define NOSAVESLOT 0 //slot where Play Without Saving appears
#define MARATHONSLOT 420 // just has to be nonzero, but let's use one that'll show up as an obvious error if something goes wrong while not using our existing saves
#define BwehHehHe() S_StartSound(NULL, sfx_bewar1+M_RandomKey(4)) // Bweh heh he
#define BwehHehHe() S_StartSoundFromEverywhere(sfx_bewar1+M_RandomKey(4)) // Bweh heh he
void M_TutorialSaveControlResponse(INT32 ch);
......@@ -485,6 +484,7 @@ UINT16 M_GetColorIndex(UINT16 color);
menucolor_t* M_GetColorFromIndex(UINT16 index);
void M_InitPlayerSetupColors(void);
void M_FreePlayerSetupColors(void);
void M_RegisterCustomCVOption(consvar_t* cvar);
// These defines make it a little easier to make menus
#define DEFAULTMENUSTYLE(id, header, source, prev, x, y)\
......@@ -523,7 +523,7 @@ void M_FreePlayerSetupColors(void);
M_DrawPauseMenu,\
x, y,\
0,\
NULL\
M_QuitPauseMenu\
}
#define CENTERMENUSTYLE(id, header, source, prev, y)\
......