Merge remote-tracking branch 'public-gitlab/next' into addons-backport

This commit is contained in:
mazmazz 2018-12-15 20:52:46 -05:00
commit 37950341ec
95 changed files with 3175 additions and 1649 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0)
project(SRB2
VERSION 2.1.20
VERSION 2.1.21
LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View File

@ -1549,6 +1549,9 @@ HW3SOUND for 3D hardware sound support
<Unit filename="src/lua_baselib.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/lua_blockmaplib.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="src/lua_consolelib.c">
<Option compilerVar="CC" />
</Unit>

View File

@ -1,4 +1,4 @@
version: 2.1.20.{branch}-{build}
version: 2.1.21.{branch}-{build}
os: MinGW
environment:

Binary file not shown.

43
libs/DLL-README.txt Normal file
View File

@ -0,0 +1,43 @@
# SRB2 - Which DLLs do I need to bundle?
Updated 12/4/2018 (v2.1.21)
Here are the required DLLs, per build. For each architecture, copy all the binaries from these folders:
* libs\dll-binaries\[i686/x86_64]
* libs\SDL2\[i686/x86_64]...\bin
* libs\SDL2_mixer\[i686/x86_64]...\bin
and don't forget to build r_opengl.dll for srb2dd.
## srb2win, 32-bit
* libs\dll-binaries\i686\exchndl.dll
* libs\dll-binaries\i686\libgme.dll
* libs\dll-binaries\i686\mgwhelp.dll (depend for exchndl.dll)
* libs\SDL2\i686-w64-mingw32\bin\SDL2.dll
* libs\SDL2_mixer\i686-w64-mingw32\bin\*.dll (get everything)
## srb2win, 64-bit
* libs\dll-binaries\x86_64\exchndl.dll
* libs\dll-binaries\x86_64\libgme.dll
* libs\dll-binaries\x86_64\mgwhelp.dll (depend for exchndl.dll)
* libs\SDL2\x86_64-w64-mingw32\bin\SDL2.dll
* libs\SDL2_mixer\x86_64-w64-mingw32\bin\*.dll (get everything)
## srb2dd, 32-bit
* libs\dll-binaries\i686\exchndl.dll
* libs\dll-binaries\i686\fmodex.dll
* libs\dll-binaries\i686\libgme.dll
* libs\dll-binaries\i686\mgwhelp.dll (depend for exchndl.dll)
* r_opengl.dll (build this from make)
## srb2dd, 64-bit
* libs\dll-binaries\x86_64\exchndl.dll
* libs\dll-binaries\x86_64\fmodex.dll
* libs\dll-binaries\x86_64\libgme.dll
* libs\dll-binaries\x86_64\mgwhelp.dll (depend for exchndl.dll)
* r_opengl.dll (build this from make)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -237,6 +237,7 @@ if(${SRB2_CONFIG_HAVE_BLUA})
add_definitions(-DHAVE_BLUA)
set(SRB2_LUA_SOURCES
lua_baselib.c
lua_blockmaplib.c
lua_consolelib.c
lua_hooklib.c
lua_hudlib.c

View File

@ -39,6 +39,7 @@ OBJS:=$(OBJS) \
$(OBJDIR)/lvm.o \
$(OBJDIR)/lua_script.o \
$(OBJDIR)/lua_baselib.o \
$(OBJDIR)/lua_blockmaplib.o \
$(OBJDIR)/lua_mathlib.o \
$(OBJDIR)/lua_hooklib.o \
$(OBJDIR)/lua_consolelib.o \

View File

@ -32,6 +32,7 @@
#include "hu_stuff.h"
#include "p_setup.h"
#include "lua_script.h"
#include "d_netfil.h" // findfile
//========
// protos.
@ -49,6 +50,7 @@ static void COM_Wait_f(void);
static void COM_Help_f(void);
static void COM_Toggle_f(void);
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr);
static boolean CV_Command(void);
static consvar_t *CV_FindVar(const char *name);
static const char *CV_StringValue(const char *var_name);
@ -62,7 +64,19 @@ CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}};
CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}};
CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
// Filter consvars by MODVERSION
// First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20)
// Also set CV_HIDEN during runtime, after config is loaded
consvar_t cv_execversion = {"execversion","25",0,CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
// for default joyaxis detection
static boolean joyaxis_default = false;
static boolean joyaxis2_default = false;
static INT32 joyaxis_count = 0;
static INT32 joyaxis2_count = 0;
#define COM_BUF_SIZE 8192 // command buffer size
#define MAX_ALIAS_RECURSION 100 // max recursion allowed for aliases
static INT32 com_wait; // one command per frame (for cmd sequences)
@ -485,6 +499,7 @@ static void COM_ExecuteString(char *ptext)
{
xcommand_t *cmd;
cmdalias_t *a;
static INT32 recursion = 0; // detects recursion and stops it if it goes too far
COM_TokenizeString(ptext);
@ -497,6 +512,7 @@ static void COM_ExecuteString(char *ptext)
{
if (!stricmp(com_argv[0], cmd->name)) //case insensitive now that we have lower and uppercase!
{
recursion = 0;
cmd->function();
return;
}
@ -507,11 +523,20 @@ static void COM_ExecuteString(char *ptext)
{
if (!stricmp(com_argv[0], a->name))
{
if (recursion > MAX_ALIAS_RECURSION)
{
CONS_Alert(CONS_WARNING, M_GetText("Alias recursion cycle detected!\n"));
recursion = 0;
return;
}
recursion++;
COM_BufInsertText(a->value);
return;
}
}
recursion = 0;
// check cvars
// Hurdler: added at Ebola's request ;)
// (don't flood the console in software mode with bad gr_xxx command)
@ -617,6 +642,7 @@ static void COM_CEchoDuration_f(void)
static void COM_Exec_f(void)
{
UINT8 *buf = NULL;
char filename[256];
if (COM_Argc() < 2 || COM_Argc() > 3)
{
@ -625,13 +651,23 @@ static void COM_Exec_f(void)
}
// load file
// Try with Argv passed verbatim first, for back compat
FIL_ReadFile(COM_Argv(1), &buf);
if (!buf)
{
if (!COM_CheckParm("-noerror"))
CONS_Printf(M_GetText("couldn't execute file %s\n"), COM_Argv(1));
return;
// Now try by searching the file path
// filename is modified with the full found path
strcpy(filename, COM_Argv(1));
if (findfile(filename, NULL, true) != FS_NOTFOUND)
FIL_ReadFile(filename, &buf);
if (!buf)
{
if (!COM_CheckParm("-noerror"))
CONS_Printf(M_GetText("couldn't execute file %s\n"), COM_Argv(1));
return;
}
}
if (!COM_CheckParm("-silent"))
@ -1220,7 +1256,7 @@ static void Got_NetVar(UINT8 **p, INT32 playernum)
char *svalue;
UINT8 stealth = false;
if (playernum != serverplayer && playernum != adminplayer && !serverloading)
if (playernum != serverplayer && !IsPlayerAdmin(playernum) && !serverloading)
{
// not from server or remote admin, must be hacked/buggy client
CONS_Alert(CONS_WARNING, M_GetText("Illegal netvar command received from %s\n"), player_names[playernum]);
@ -1349,7 +1385,7 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth)
// send the value of the variable
XBOXSTATIC UINT8 buf[128];
UINT8 *p = buf;
if (!(server || (adminplayer == consoleplayer)))
if (!(server || (IsPlayerAdmin(consoleplayer))))
{
CONS_Printf(M_GetText("Only the server or admin can change: %s %s\n"), var->name, var->string);
return;
@ -1556,6 +1592,200 @@ void CV_AddValue(consvar_t *var, INT32 increment)
var->changed = 1; // user has changed it now
}
void CV_InitFilterVar(void)
{
joyaxis_default = joyaxis2_default = true;
joyaxis_count = joyaxis2_count = 0;
}
static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
{
// If ALL axis settings are previous defaults, set them to the new defaults
// MODVERSION < 26 (2.1.21)
if (joyaxis_default)
{
#if !defined (_WII) && !defined (WMINPUT)
if (!stricmp(v->name, "joyaxis_turn"))
{
if (joyaxis_count > 6) return false;
// we're currently setting the new defaults, don't interfere
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "X-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
#if !defined (PSP)
if (!stricmp(v->name, "joyaxis_move"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "Y-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
#endif
#if !defined (_arch_dreamcast) && !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis_side"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "Z-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
#endif
#if !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis_look"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis_count++;
else joyaxis_default = false;
}
#endif
if (!stricmp(v->name, "joyaxis_fire")
|| !stricmp(v->name, "joyaxis_firenormal"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis_count++;
else joyaxis_default = false;
}
#endif
// reset all axis settings to defaults
if (joyaxis_count == 6)
{
COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis.name, cv_turnaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis.name, cv_moveaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis.name, cv_sideaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis.name, cv_lookaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis.name, cv_fireaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis.name, cv_firenaxis.defaultvalue));
joyaxis_count++;
return false;
}
}
if (joyaxis2_default)
{
#if !defined (_WII) && !defined (WMINPUT)
if (!stricmp(v->name, "joyaxis2_turn"))
{
if (joyaxis2_count > 6) return false;
// we're currently setting the new defaults, don't interfere
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "X-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
// #if !defined (PSP)
if (!stricmp(v->name, "joyaxis2_move"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "Y-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
// #endif
#if !defined (_arch_dreamcast) && !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis2_side"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "Z-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
#endif
#if !defined (_XBOX) // && !defined (PSP)
if (!stricmp(v->name, "joyaxis2_look"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis2_count++;
else joyaxis2_default = false;
}
#endif
if (!stricmp(v->name, "joyaxis2_fire")
|| !stricmp(v->name, "joyaxis2_firenormal"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis2_count++;
else joyaxis2_default = false;
}
#endif
// reset all axis settings to defaults
if (joyaxis2_count == 6)
{
COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis2.name, cv_turnaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis2.name, cv_moveaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis2.name, cv_sideaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis2.name, cv_lookaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis2.name, cv_fireaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis2.name, cv_firenaxis2.defaultvalue));
joyaxis2_count++;
return false;
}
}
// we haven't reached our counts yet, or we're not default
return true;
}
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr)
{
// True means allow the CV change, False means block it
// We only care about CV_SAVE because this filters the user's config files
// We do this same check in CV_Command
if (!(v->flags & CV_SAVE))
return true;
// We go by MODVERSION here
if (cv_execversion.value < 26) // 26 = 2.1.21
{
// MOUSE SETTINGS
// alwaysfreelook split between first and third person (chasefreelook)
// mousemove was on by default, which invalidates the current approach
if (!stricmp(v->name, "alwaysmlook")
|| !stricmp(v->name, "alwaysmlook2")
|| !stricmp(v->name, "mousemove")
|| !stricmp(v->name, "mousemove2"))
return false;
// mousesens was changed from 35 to 20 due to oversensitivity
if ((!stricmp(v->name, "mousesens")
|| !stricmp(v->name, "mousesens2")
|| !stricmp(v->name, "mouseysens")
|| !stricmp(v->name, "mouseysens2"))
&& atoi(valstr) == 35)
return false;
// JOYSTICK DEFAULTS
// use_joystick was changed from 0 to 1 to automatically use a joystick if available
#if defined(HAVE_SDL) || defined(_WINDOWS)
if ((!stricmp(v->name, "use_joystick")
|| !stricmp(v->name, "use_joystick2"))
&& atoi(valstr) == 0)
return false;
#endif
// axis defaults were changed to be friendly to 360 controllers
// if ALL axis settings are defaults, then change them to new values
if (!CV_FilterJoyAxisVars(v, valstr))
return false;
}
return true;
}
/** Displays or changes a variable from the console.
* Since the user is presumed to have been directly responsible
* for this change, the variable is marked as changed this game.
@ -1580,8 +1810,11 @@ static boolean CV_Command(void)
return true;
}
CV_Set(v, COM_Argv(1));
v->changed = 1; // now it's been changed by (presumably) the user
if (!(v->flags & CV_SAVE) || CV_FilterVarByVersion(v, COM_Argv(1)))
{
CV_Set(v, COM_Argv(1));
v->changed = 1; // now it's been changed by (presumably) the user
}
return true;
}

View File

@ -125,6 +125,12 @@ extern CV_PossibleValue_t CV_OnOff[];
extern CV_PossibleValue_t CV_YesNo[];
extern CV_PossibleValue_t CV_Unsigned[];
extern CV_PossibleValue_t CV_Natural[];
// Filter consvars by version
extern consvar_t cv_execversion;
void CV_InitFilterVar(void);
// register a variable for use at the console
void CV_RegisterVar(consvar_t *variable);

View File

@ -25,6 +25,7 @@
#include "g_game.h"
#include "hu_stuff.h"
#include "keys.h"
#include "g_input.h" // JOY1
#include "m_menu.h"
#include "console.h"
#include "d_netfil.h"
@ -1365,15 +1366,18 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.adminplayer = (SINT8)adminplayer;
// we fill these structs with FFs so that any players not in game get sent as 0xFFFF
// which is nice and easy for us to detect
memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins));
memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor));
memset(netbuffer->u.servercfg.adminplayers, -1, sizeof(netbuffer->u.servercfg.adminplayers));
for (i = 0; i < MAXPLAYERS; i++)
{
netbuffer->u.servercfg.adminplayers[i] = (SINT8)adminplayers[i];
if (!playeringame[i])
continue;
netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin;
@ -1959,7 +1963,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
I_OsPolling();
key = I_GetKey();
if (key == KEY_ESCAPE)
if (key == KEY_ESCAPE || key == KEY_JOY1+1)
{
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
@ -2042,7 +2046,7 @@ static void CL_ConnectToServer(boolean viams)
G_SetGamestate(GS_WAITINGPLAYERS);
wipegamestate = GS_WAITINGPLAYERS;
adminplayer = -1;
ClearAdminPlayers();
pnumnodes = 1;
oldtic = I_GetTime() - 1;
#ifndef NONET
@ -2354,7 +2358,7 @@ void CL_ClearPlayer(INT32 playernum)
//
// Removes a player from the current game
//
static void CL_RemovePlayer(INT32 playernum)
static void CL_RemovePlayer(INT32 playernum, INT32 reason)
{
// Sanity check: exceptional cases (i.e. c-fails) can cause multiple
// kick commands to be issued for the same player.
@ -2409,6 +2413,10 @@ static void CL_RemovePlayer(INT32 playernum)
}
}
#ifdef HAVE_BLUA
LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting
#endif
// Reset player data
CL_ClearPlayer(playernum);
@ -2421,8 +2429,10 @@ static void CL_RemovePlayer(INT32 playernum)
// Reset the name
sprintf(player_names[playernum], "Player %d", playernum+1);
if (playernum == adminplayer)
adminplayer = -1; // don't stay admin after you're gone
if (IsPlayerAdmin(playernum))
{
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
}
if (playernum == displayplayer)
displayplayer = consoleplayer; // don't look through someone's view who isn't there
@ -2540,7 +2550,7 @@ static void Command_Nodes(void)
if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL)
CONS_Printf(" - %s", address);
if (i == adminplayer)
if (IsPlayerAdmin(i))
CONS_Printf(M_GetText(" (verified admin)"));
if (players[i].spectator)
@ -2565,7 +2575,7 @@ static void Command_Ban(void)
return;
}
if (server || adminplayer == consoleplayer)
if (server || IsPlayerAdmin(consoleplayer))
{
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf;
@ -2631,7 +2641,7 @@ static void Command_Kick(void)
return;
}
if (server || adminplayer == consoleplayer)
if (server || IsPlayerAdmin(consoleplayer))
{
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf;
@ -2640,13 +2650,16 @@ static void Command_Kick(void)
if (pn == -1 || pn == 0)
return;
// Special case if we are trying to kick a player who is downloading the game state:
// trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading
if (sendingsavegame[playernode[pn]])
if (server)
{
Net_ConnectionTimeout(playernode[pn]);
return;
// Special case if we are trying to kick a player who is downloading the game state:
// trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading
if (sendingsavegame[playernode[pn]])
{
Net_ConnectionTimeout(playernode[pn]);
return;
}
}
WRITESINT8(p, pn);
@ -2684,11 +2697,12 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
INT32 pnum, msg;
XBOXSTATIC char buf[3 + MAX_REASONLENGTH];
char *reason = buf;
kickreason_t kickreason = KR_KICK;
pnum = READUINT8(*p);
msg = READUINT8(*p);
if (pnum == serverplayer && playernum == adminplayer)
if (pnum == serverplayer && IsPlayerAdmin(playernum))
{
CONS_Printf(M_GetText("Server is being shut down remotely. Goodbye!\n"));
@ -2699,7 +2713,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
}
// Is playernum authorized to make this kick?
if (playernum != serverplayer && playernum != adminplayer
if (playernum != serverplayer && !IsPlayerAdmin(playernum)
&& !(playerpernode[playernode[playernum]] == 2
&& nodetoplayer2[playernode[playernum]] == pnum))
{
@ -2766,14 +2780,17 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
{
case KICK_MSG_GO_AWAY:
CONS_Printf(M_GetText("has been kicked (Go away)\n"));
kickreason = KR_KICK;
break;
#ifdef NEWPING
case KICK_MSG_PING_HIGH:
CONS_Printf(M_GetText("left the game (Broke ping limit)\n"));
kickreason = KR_PINGLIMIT;
break;
#endif
case KICK_MSG_CON_FAIL:
CONS_Printf(M_GetText("left the game (Synch failure)\n"));
kickreason = KR_SYNCH;
if (M_CheckParm("-consisdump")) // Helps debugging some problems
{
@ -2810,21 +2827,26 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
break;
case KICK_MSG_TIMEOUT:
CONS_Printf(M_GetText("left the game (Connection timeout)\n"));
kickreason = KR_TIMEOUT;
break;
case KICK_MSG_PLAYER_QUIT:
if (netgame) // not splitscreen/bots
CONS_Printf(M_GetText("left the game\n"));
kickreason = KR_LEAVE;
break;
case KICK_MSG_BANNED:
CONS_Printf(M_GetText("has been banned (Don't come back)\n"));
kickreason = KR_BAN;
break;
case KICK_MSG_CUSTOM_KICK:
READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
CONS_Printf(M_GetText("has been kicked (%s)\n"), reason);
kickreason = KR_KICK;
break;
case KICK_MSG_CUSTOM_BAN:
READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
CONS_Printf(M_GetText("has been banned (%s)\n"), reason);
kickreason = KR_BAN;
break;
}
@ -2852,7 +2874,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING);
}
else
CL_RemovePlayer(pnum);
CL_RemovePlayer(pnum, kickreason);
}
consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
@ -2962,6 +2984,7 @@ void SV_ResetServer(void)
playeringame[i] = false;
playernode[i] = UINT8_MAX;
sprintf(player_names[i], "Player %d", i + 1);
adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
}
mynode = 0;
@ -3036,7 +3059,7 @@ void D_QuitNetGame(void)
}
D_CloseConnection();
adminplayer = -1;
ClearAdminPlayers();
DEBFILE("===========================================================================\n"
" Log finish\n"
@ -3067,7 +3090,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
INT16 node, newplayernum;
boolean splitscreenplayer;
if (playernum != serverplayer && playernum != adminplayer)
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
// protect against hacked/buggy client
CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]);
@ -3592,7 +3615,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
gametype = netbuffer->u.servercfg.gametype;
modifiedgame = netbuffer->u.servercfg.modifiedgame;
adminplayer = netbuffer->u.servercfg.adminplayer;
for (j = 0; j < MAXPLAYERS; j++)
adminplayers[j] = netbuffer->u.servercfg.adminplayers[j];
memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
}
@ -4461,6 +4485,7 @@ static void Local_Maketic(INT32 realtics)
void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle)
{
tic_t tic;
UINT8 numadjust = 0;
(void)x;
(void)y;
@ -4470,7 +4495,21 @@ void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle)
// spawning, but will be applied afterwards.
for (tic = server ? maketic : (neededtic - 1); tic >= gametic; tic--)
{
if (numadjust++ == BACKUPTICS)
{
DEBFILE(va("SV_SpawnPlayer: All netcmds for player %d adjusted!\n", playernum));
// We already adjusted them all, waste of time doing the same thing over and over
// This shouldn't happen normally though, either gametic was 0 (which is handled now anyway)
// or maketic >= gametic + BACKUPTICS
// -- Monster Iestyn 16/01/18
break;
}
netcmds[tic%BACKUPTICS][playernum].angleturn = (INT16)((angle>>16) | TICCMD_RECEIVED);
if (!tic) // failsafe for gametic == 0 -- Monster Iestyn 16/01/18
break;
}
}
// create missed tic

View File

@ -282,7 +282,7 @@ typedef struct
UINT8 gametype;
UINT8 modifiedgame;
SINT8 adminplayer; // Needs to be signed
SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed
char server_context[8]; // Unique context id, generated at server startup.
@ -445,6 +445,17 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_KICK 7
#define KICK_MSG_CUSTOM_BAN 8
typedef enum
{
KR_KICK = 1, //Kicked by server
KR_PINGLIMIT = 2, //Broke Ping Limit
KR_SYNCH = 3, //Synch Failure
KR_TIMEOUT = 4, //Connection Timeout
KR_BAN = 5, //Banned by server
KR_LEAVE = 6, //Quit the game
} kickreason_t;
extern boolean server;
#define client (!server)
extern boolean dedicated; // For dedicated server

View File

@ -27,6 +27,7 @@
#include "d_clisrv.h"
#include "z_zone.h"
#include "i_tcp.h"
#include "d_main.h" // srb2home
//
// NETWORKING
@ -1374,12 +1375,12 @@ boolean D_CheckNetGame(void)
{
k++;
sprintf(filename, "debug%d.txt", k);
debugfile = fopen(filename, "w");
debugfile = fopen(va("%s" PATHSEP "%s", srb2home, filename), "w");
}
if (debugfile)
CONS_Printf(M_GetText("debug output to: %s\n"), filename);
CONS_Printf(M_GetText("debug output to: %s\n"), va("%s" PATHSEP "%s", srb2home, filename));
else
CONS_Alert(CONS_WARNING, M_GetText("cannot debug output to file %s!\n"), filename);
CONS_Alert(CONS_WARNING, M_GetText("cannot debug output to file %s!\n"), va("%s" PATHSEP "%s", srb2home, filename));
}
#endif
#endif

View File

@ -145,7 +145,9 @@ static void Command_Changepassword_f(void);
static void Command_Login_f(void);
static void Got_Login(UINT8 **cp, INT32 playernum);
static void Got_Verification(UINT8 **cp, INT32 playernum);
static void Got_Removal(UINT8 **cp, INT32 playernum);
static void Command_Verify_f(void);
static void Command_RemoveAdmin_f(void);
static void Command_MotD_f(void);
static void Got_MotD_f(UINT8 **cp, INT32 playernum);
@ -241,7 +243,7 @@ INT32 cv_debug;
consvar_t cv_usemouse = {"use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_usemouse2 = {"use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2, 0, NULL, NULL, 0, 0, NULL};
#if defined (DC) || defined (_XBOX) || defined (WMINPUT) || defined (_WII) //joystick 1 and 2
#if defined (DC) || defined (_XBOX) || defined (WMINPUT) || defined (_WII) || defined(HAVE_SDL) || defined(_WINDOWS) //joystick 1 and 2
consvar_t cv_usejoystick = {"use_joystick", "1", CV_SAVE|CV_CALL, usejoystick_cons_t,
I_InitJoystick, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_usejoystick2 = {"use_joystick2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t,
@ -318,7 +320,6 @@ consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL,
consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display
static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}};
consvar_t cv_pointlimit = {"pointlimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t,
PointLimit_OnChange, 0, NULL, NULL, 0, 0, NULL};
@ -366,7 +367,7 @@ consvar_t cv_sleep = {"cpusleep", "-1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL
INT16 gametype = GT_COOP;
boolean splitscreen = false;
boolean circuitmap = false;
INT32 adminplayer = -1;
INT32 adminplayers[MAXPLAYERS];
/// \warning Keep this up-to-date if you add/remove/rename net text commands
const char *netxcmdnames[MAXNETXCMD - 1] =
@ -428,8 +429,10 @@ void D_RegisterServerCommands(void)
COM_AddCommand("password", Command_Changepassword_f);
RegisterNetXCmd(XD_LOGIN, Got_Login);
COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin
COM_AddCommand("verify", Command_Verify_f);
COM_AddCommand("promote", Command_Verify_f);
RegisterNetXCmd(XD_VERIFIED, Got_Verification);
COM_AddCommand("demote", Command_RemoveAdmin_f);
RegisterNetXCmd(XD_DEMOTED, Got_Removal);
COM_AddCommand("motd", Command_MotD_f);
RegisterNetXCmd(XD_SETMOTD, Got_MotD_f); // For remote admin
@ -675,6 +678,8 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_crosshair2);
CV_RegisterVar(&cv_alwaysfreelook);
CV_RegisterVar(&cv_alwaysfreelook2);
CV_RegisterVar(&cv_chasefreelook);
CV_RegisterVar(&cv_chasefreelook2);
// g_input.c
CV_RegisterVar(&cv_sideaxis);
@ -1014,7 +1019,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true;
// Force skin in effect.
if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
if (client && (cv_forceskin.value != -1) && !(IsPlayerAdmin(playernum) && serverplayer == -1))
return false;
// Can change skin in intermission and whatnot.
@ -1165,7 +1170,7 @@ static void SendNameAndColor(void)
snacpending++;
// Don't change name if muted
if (cv_mute.value && !(server || adminplayer == consoleplayer))
if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
CV_StealthSet(&cv_playername, player_names[consoleplayer]);
else // Cleanup name if changing it
CleanupPlayerName(consoleplayer, cv_playername.zstring);
@ -1452,7 +1457,12 @@ static void Command_Playdemo_f(void)
CONS_Printf(M_GetText("Playing back demo '%s'.\n"), name);
G_DoPlayDemo(name);
// Internal if no extension, external if one exists
// If external, convert the file name to a path in SRB2's home directory
if (FIL_CheckExtension(name))
G_DoPlayDemo(va("%s"PATHSEP"%s", srb2home, name));
else
G_DoPlayDemo(name);
}
static void Command_Timedemo_f(void)
@ -1572,7 +1582,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
mapchangepending = 0;
// spawn the server if needed
// reset players if there is a new one
if (!(adminplayer == consoleplayer))
if (!IsPlayerAdmin(consoleplayer))
{
if (SV_SpawnServer())
buf[0] &= ~(1<<1);
@ -1630,7 +1640,7 @@ static void Command_Map_f(void)
return;
}
if (client && !(adminplayer == consoleplayer))
if (client && !IsPlayerAdmin(consoleplayer))
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
@ -1758,8 +1768,11 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
UINT8 flags;
INT32 resetplayer = 1, lastgametype;
UINT8 skipprecutscene, FLS;
#ifdef HAVE_BLUA
INT16 mapnumber;
#endif
if (playernum != serverplayer && playernum != adminplayer)
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal map change received from %s\n"), player_names[playernum]);
if (server)
@ -1819,7 +1832,8 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
}
#ifdef HAVE_BLUA
LUAh_MapChange();
mapnumber = M_MapNumber(mapname[3], mapname[4]);
LUAh_MapChange(mapnumber);
#endif
G_InitNew(ultimatemode, mapname, resetplayer, skipprecutscene);
@ -1860,7 +1874,7 @@ static void Command_Pause(void)
else
WRITEUINT8(cp, 0);
if (cv_pause.value || server || (adminplayer == consoleplayer))
if (cv_pause.value || server || (IsPlayerAdmin(consoleplayer)))
{
if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION))
{
@ -1878,7 +1892,7 @@ static void Got_Pause(UINT8 **cp, INT32 playernum)
UINT8 dedicatedpause = false;
const char *playername;
if (netgame && !cv_pause.value && playernum != serverplayer && playernum != adminplayer)
if (netgame && !cv_pause.value && playernum != serverplayer && !IsPlayerAdmin(playernum))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal pause command received from %s\n"), player_names[playernum]);
if (server)
@ -2007,7 +2021,7 @@ static void Got_RandomSeed(UINT8 **cp, INT32 playernum)
*/
static void Command_Clearscores_f(void)
{
if (!(server || (adminplayer == consoleplayer)))
if (!(server || (IsPlayerAdmin(consoleplayer))))
return;
SendNetXCmd(XD_CLEARSCORES, NULL, 1);
@ -2027,7 +2041,7 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum)
INT32 i;
(void)cp;
if (playernum != serverplayer && playernum != adminplayer)
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal clear scores command received from %s\n"), player_names[playernum]);
if (server)
@ -2248,7 +2262,7 @@ static void Command_ServerTeamChange_f(void)
UINT16 usvalue;
NetPacket.value.l = NetPacket.value.b = 0;
if (!(server || (adminplayer == consoleplayer)))
if (!(server || (IsPlayerAdmin(consoleplayer))))
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
@ -2395,7 +2409,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
if (NetPacket.packet.verification) // Special marker that the server sent the request
{
if (playernum != serverplayer && (playernum != adminplayer))
if (playernum != serverplayer && (!IsPlayerAdmin(playernum)))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
if (server)
@ -2434,7 +2448,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
}
else
{
if (playernum != serverplayer && (playernum != adminplayer))
if (playernum != serverplayer && (!IsPlayerAdmin(playernum)))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]);
if (server)
@ -2703,6 +2717,12 @@ static void Command_Login_f(void)
XBOXSTATIC UINT8 finalmd5[16];
const char *pw;
if (!netgame)
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
// If the server uses login, it will effectively just remove admin privileges
// from whoever has them. This is good.
if (COM_Argc() != 2)
@ -2751,13 +2771,56 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
if (!memcmp(sentmd5, finalmd5, 16))
{
CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[playernum]);
COM_BufInsertText(va("verify %d\n", playernum)); // do this immediately
COM_BufInsertText(va("promote %d\n", playernum)); // do this immediately
}
else
CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[playernum]);
#endif
}
boolean IsPlayerAdmin(INT32 playernum)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
if (playernum == adminplayers[i])
return true;
return false;
}
void SetAdminPlayer(INT32 playernum)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playernum == adminplayers[i])
return; // Player is already admin
if (adminplayers[i] == -1)
{
adminplayers[i] = playernum; // Set the player to a free spot
break; // End the loop now. If it keeps going, the same player might get assigned to two slots.
}
}
}
void ClearAdminPlayers(void)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
adminplayers[i] = -1;
}
void RemoveAdminPlayer(INT32 playernum)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
if (playernum == adminplayers[i])
adminplayers[i] = -1;
}
static void Command_Verify_f(void)
{
XBOXSTATIC char buf[8]; // Should be plenty
@ -2770,9 +2833,15 @@ static void Command_Verify_f(void)
return;
}
if (!netgame)
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (COM_Argc() != 2)
{
CONS_Printf(M_GetText("verify <node>: give admin privileges to a node\n"));
CONS_Printf(M_GetText("promote <node>: give admin privileges to a node\n"));
return;
}
@ -2806,7 +2875,7 @@ static void Got_Verification(UINT8 **cp, INT32 playernum)
return;
}
adminplayer = num;
SetAdminPlayer(num);
if (num != consoleplayer)
return;
@ -2814,6 +2883,62 @@ static void Got_Verification(UINT8 **cp, INT32 playernum)
CONS_Printf(M_GetText("You are now a server administrator.\n"));
}
static void Command_RemoveAdmin_f(void)
{
XBOXSTATIC char buf[8]; // Should be plenty
char *temp;
INT32 playernum;
if (client)
{
CONS_Printf(M_GetText("Only the server can use this.\n"));
return;
}
if (COM_Argc() != 2)
{
CONS_Printf(M_GetText("demote <node>: remove admin privileges from a node\n"));
return;
}
strlcpy(buf, COM_Argv(1), sizeof(buf));
playernum = atoi(buf);
temp = buf;
WRITEUINT8(temp, playernum);
if (playeringame[playernum])
SendNetXCmd(XD_DEMOTED, buf, 1);
}
static void Got_Removal(UINT8 **cp, INT32 playernum)
{
INT16 num = READUINT8(*cp);
if (playernum != serverplayer) // it's not from the server (hacker or bug)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal demotion received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]);
if (server)
{
XBOXSTATIC UINT8 buf[2];
buf[0] = (UINT8)playernum;
buf[1] = KICK_MSG_CON_FAIL;
SendNetXCmd(XD_KICK, &buf, 2);
}
return;
}
RemoveAdminPlayer(num);
if (num != consoleplayer)
return;
CONS_Printf(M_GetText("You are no longer a server administrator.\n"));
}
static void Command_MotD_f(void)
{
size_t i, j;
@ -2825,7 +2950,7 @@ static void Command_MotD_f(void)
return;
}
if (!(server || (adminplayer == consoleplayer)))
if (!(server || (IsPlayerAdmin(consoleplayer))))
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
@ -2849,7 +2974,7 @@ static void Command_MotD_f(void)
}
if ((netgame || multiplayer) && client)
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
SendNetXCmd(XD_SETMOTD, mymotd, i); // send the actual size of the motd string, not the full buffer's size
else
{
strcpy(motd, mymotd);
@ -2872,7 +2997,7 @@ static void Got_MotD_f(UINT8 **cp, INT32 playernum)
if (!isprint(mymotd[i]) || mymotd[i] == ';')
kick = true;
if ((playernum != serverplayer && playernum != adminplayer) || kick)
if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal motd change received from %s\n"), player_names[playernum]);
if (server)
@ -2909,7 +3034,7 @@ static void Command_RunSOC(void)
else
fn = COM_Argv(1);
if (netgame && !(server || consoleplayer == adminplayer))
if (netgame && !(server || IsPlayerAdmin(consoleplayer)))
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
@ -2935,7 +3060,7 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum)
char filename[256];
filestatus_t ncs = FS_NOTFOUND;
if (playernum != serverplayer && playernum != adminplayer)
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal runsoc command received from %s\n"), player_names[playernum]);
if (server)
@ -3006,7 +3131,7 @@ static void Command_Addfile(void)
if (!musiconly)
{
// ... But only so long as they contain nothing more then music and sprites.
if (netgame && !(server || adminplayer == consoleplayer))
if (netgame && !(server || IsPlayerAdmin(consoleplayer)))
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
@ -3017,7 +3142,7 @@ static void Command_Addfile(void)
// Add file on your client directly if it is trivial, or you aren't in a netgame.
if (!(netgame || multiplayer) || musiconly)
{
P_AddWadFile(fn, NULL);
P_AddWadFile(fn);
return;
}
@ -3068,7 +3193,7 @@ static void Command_Addfile(void)
WRITEMEM(buf_p, md5sum, 16);
}
if (adminplayer == consoleplayer) // Request to add file
if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file
SendNetXCmd(XD_REQADDFILE, buf, buf_p - buf);
else
SendNetXCmd(XD_ADDFILE, buf, buf_p - buf);
@ -3117,7 +3242,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
UINT8 md5sum[16];
boolean kick = false;
boolean toomany = false;
INT32 i;
INT32 i,j;
size_t packetsize = 0;
serverinfo_pak *dummycheck = NULL;
@ -3136,7 +3261,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
if (!isprint(filename[i]) || filename[i] == ';')
kick = true;
if ((playernum != serverplayer && playernum != adminplayer) || kick)
if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick)
{
XBOXSTATIC UINT8 buf[2];
@ -3170,8 +3295,9 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
CONS_Printf("%s",message);
if (adminplayer)
COM_BufAddText(va("sayto %d %s", adminplayer, message));
for (j = 0; j < MAXPLAYERS; j++)
if (adminplayers[j])
COM_BufAddText(va("sayto %d %s", adminplayers[j], message));
return;
}
@ -3231,7 +3357,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
ncs = findfile(filename,md5sum,true);
if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL))
if (ncs != FS_FOUND || !P_AddWadFile(filename))
{
Command_ExitGame_f();
if (ncs == FS_FOUND)
@ -3286,10 +3412,51 @@ static void Command_ListWADS_f(void)
static void Command_Version_f(void)
{
#ifdef DEVELOP
CONS_Printf("Sonic Robo Blast 2 %s-%s (%s %s)\n", compbranch, comprevision, compdate, comptime);
CONS_Printf("Sonic Robo Blast 2 %s-%s (%s %s) ", compbranch, comprevision, compdate, comptime);
#else
CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s)\n", VERSIONSTRING, compdate, comptime, comprevision);
CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision);
#endif
// Base library
#if defined( HAVE_SDL)
CONS_Printf("SDL ");
#elif defined(_WINDOWS)
CONS_Printf("DD ");
#endif
// OS
// Would be nice to use SDL_GetPlatform for this
#if defined (_WIN32) || defined (_WIN64)
CONS_Printf("Windows ");
#elif defined(__linux__)
CONS_Printf("Linux ");
#elif defined(MACOSX)
CONS_Printf("macOS" );
#elif defined(UNIXCOMMON)
CONS_Printf("Unix (Common) ");
#else
CONS_Printf("Other OS ");
#endif
// Bitness
if (sizeof(void*) == 4)
CONS_Printf("32-bit ");
else if (sizeof(void*) == 8)
CONS_Printf("64-bit ");
else // 16-bit? 128-bit?
CONS_Printf("Bits Unknown ");
// No ASM?
#ifdef NOASM
CONS_Printf("\x85" "NOASM " "\x80");
#endif
// Debug build
#ifdef _DEBUG
CONS_Printf("\x85" "DEBUG " "\x80");
#endif
CONS_Printf("\n");
}
#ifdef UPDATE_ALERT
@ -3568,7 +3735,7 @@ void D_GameTypeChanged(INT32 lastgametype)
if (playeringame[i])
players[i].ctfteam = 0;
if (server || (adminplayer == consoleplayer))
if (server || (IsPlayerAdmin(consoleplayer)))
{
CV_StealthSetValue(&cv_teamscramble, 0);
teamscramble = 0;
@ -3651,7 +3818,7 @@ static void TeamScramble_OnChange(void)
if (!cv_teamscramble.value)
teamscramble = 0;
if (!G_GametypeHasTeams() && (server || consoleplayer == adminplayer))
if (!G_GametypeHasTeams() && (server || IsPlayerAdmin(consoleplayer)))
{
CONS_Alert(CONS_NOTICE, M_GetText("This command cannot be used in this gametype.\n"));
CV_StealthSetValue(&cv_teamscramble, 0);
@ -3830,7 +3997,7 @@ static void Command_ExitLevel_f(void)
{
if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug)
CONS_Printf(M_GetText("This only works in a netgame.\n"));
else if (!(server || (adminplayer == consoleplayer)))
else if (!(server || (IsPlayerAdmin(consoleplayer))))
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
else if (gamestate != GS_LEVEL || demoplayback)
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
@ -3846,7 +4013,7 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
if (gameaction == ga_completed)
return;
if (playernum != serverplayer && playernum != adminplayer)
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal exitlevel command received from %s\n"), player_names[playernum]);
if (server)
@ -3954,7 +4121,7 @@ static void Command_Cheats_f(void)
{
if (COM_CheckParm("off"))
{
if (!(server || (adminplayer == consoleplayer)))
if (!(server || (IsPlayerAdmin(consoleplayer))))
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
else
CV_ResetCheatNetVars();
@ -3964,7 +4131,7 @@ static void Command_Cheats_f(void)
if (CV_CheatsEnabled())
{
CONS_Printf(M_GetText("At least one CHEAT-marked variable has been changed -- Cheats are enabled.\n"));
if (server || (adminplayer == consoleplayer))
if (server || (IsPlayerAdmin(consoleplayer)))
CONS_Printf(M_GetText("Type CHEATS OFF to reset all cheat variables to default.\n"));
}
else
@ -4033,7 +4200,7 @@ static void Command_Archivetest_f(void)
*/
static void ForceSkin_OnChange(void)
{
if ((server || adminplayer == consoleplayer) && (cv_forceskin.value < -1 || cv_forceskin.value >= numskins))
if ((server || IsPlayerAdmin(consoleplayer)) && (cv_forceskin.value < -1 || cv_forceskin.value >= numskins))
{
if (cv_forceskin.value == -2)
CV_SetValue(&cv_forceskin, numskins-1);
@ -4063,7 +4230,7 @@ static void ForceSkin_OnChange(void)
//Allows the player's name to be changed if cv_mute is off.
static void Name_OnChange(void)
{
if (cv_mute.value && !(server || adminplayer == consoleplayer))
if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
{
CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n"));
CV_StealthSet(&cv_playername, player_names[consoleplayer]);
@ -4186,7 +4353,7 @@ static void Color2_OnChange(void)
*/
static void Mute_OnChange(void)
{
if (server || (adminplayer == consoleplayer))
if (server || (IsPlayerAdmin(consoleplayer)))
return;
if (cv_mute.value)

View File

@ -133,9 +133,10 @@ typedef enum
XD_DELFILE, // 18
XD_SETMOTD, // 19
XD_SUICIDE, // 20
XD_DEMOTED, // 21
#ifdef HAVE_BLUA
XD_LUACMD, // 21
XD_LUAVAR, // 22
XD_LUACMD, // 22
XD_LUAVAR, // 23
#endif
MAXNETXCMD
} netxcmd_t;
@ -190,6 +191,10 @@ void Command_ExitGame_f(void);
void Command_Retry_f(void);
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
boolean IsPlayerAdmin(INT32 playernum);
void SetAdminPlayer(INT32 playernum);
void ClearAdminPlayers(void);
void RemoveAdminPlayer(INT32 playernum);
void ItemFinder_OnChange(void);
void D_SetPassword(const char *pw);

View File

@ -425,7 +425,7 @@ void CL_LoadServerFiles(void)
continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND)
{
P_AddWadFile(fileneeded[i].filename, NULL);
P_AddWadFile(fileneeded[i].filename);
G_SetGameModified(true);
fileneeded[i].status = FS_OPEN;
}

View File

@ -32,6 +32,7 @@
#include "fastcmp.h"
#include "lua_script.h"
#include "lua_hook.h"
#include "d_clisrv.h"
#include "m_cond.h"
@ -1035,7 +1036,10 @@ static void readlevelheader(MYFILE *f, INT32 num)
// Get the part before the " = "
tmp = strchr(s, '=');
*(tmp-1) = '\0';
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
@ -1616,7 +1620,10 @@ static void readhuditem(MYFILE *f, INT32 num)
// Get the part before the " = "
tmp = strchr(s, '=');
*(tmp-1) = '\0';
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
@ -1860,7 +1867,6 @@ static void readframe(MYFILE *f, INT32 num)
char *word1;
char *word2 = NULL;
char *tmp;
INT32 j;
do
{
@ -1875,16 +1881,6 @@ static void readframe(MYFILE *f, INT32 num)
if (s == tmp)
continue; // Skip comment lines, but don't break.
for (j = 0; s[j] != '\n'; j++)
{
if (s[j] == '=')
{
j += 2;
j = atoi(&s[j]);
break;
}
}
word1 = strtok(s, " ");
if (word1)
strupr(word1);
@ -2129,7 +2125,10 @@ static void reademblemdata(MYFILE *f, INT32 num)
// Get the part before the " = "
tmp = strchr(s, '=');
*(tmp-1) = '\0';
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
@ -2269,7 +2268,10 @@ static void readextraemblemdata(MYFILE *f, INT32 num)
// Get the part before the " = "
tmp = strchr(s, '=');
*(tmp-1) = '\0';
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
@ -2353,7 +2355,10 @@ static void readunlockable(MYFILE *f, INT32 num)
// Get the part before the " = "
tmp = strchr(s, '=');
*(tmp-1) = '\0';
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
@ -2640,7 +2645,10 @@ static void readconditionset(MYFILE *f, UINT8 setnum)
// Get the part before the " = "
tmp = strchr(s, '=');
*(tmp-1) = '\0';
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
@ -2885,7 +2893,10 @@ static void readmaincfg(MYFILE *f)
// Get the part before the " = "
tmp = strchr(s, '=');
*(tmp-1) = '\0';
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
@ -3069,7 +3080,7 @@ static void readmaincfg(MYFILE *f)
strncpy(timeattackfolder, gamedatafilename, min(filenamelen, sizeof (timeattackfolder)));
timeattackfolder[min(filenamelen, sizeof (timeattackfolder) - 1)] = '\0';
strncpy(savegamename, timeattackfolder, strlen(timeattackfolder));
strcpy(savegamename, timeattackfolder);
strlcat(savegamename, "%u.ssg", sizeof(savegamename));
// can't use sprintf since there is %u in savegamename
strcatbf(savegamename, srb2home, PATHSEP);
@ -3124,7 +3135,10 @@ static void readwipes(MYFILE *f)
// Get the part before the " = "
tmp = strchr(s, '=');
*(tmp-1) = '\0';
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
@ -7272,6 +7286,14 @@ struct {
{"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel
{"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop.
#ifdef ESLOPE
// Slope flags
{"SL_NOPHYSICS",SL_NOPHYSICS}, // Don't do momentum adjustment with this slope
{"SL_NODYNAMIC",SL_NODYNAMIC}, // Slope will never need to move during the level, so don't fuss with recalculating it
{"SL_ANCHORVERTEX",SL_ANCHORVERTEX},// Slope is using a Slope Vertex Thing to anchor its position
{"SL_VERTEXSLOPE",SL_VERTEXSLOPE}, // Slope is built from three Slope Vertex Things
#endif
// Angles
{"ANG1",ANG1},
{"ANG2",ANG2},
@ -7395,6 +7417,14 @@ struct {
{"V_CHARCOLORSHIFT",V_CHARCOLORSHIFT},
{"V_ALPHASHIFT",V_ALPHASHIFT},
//Kick Reasons
{"KR_KICK",KR_KICK},
{"KR_PINGLIMIT",KR_PINGLIMIT},
{"KR_SYNCH",KR_SYNCH},
{"KR_TIMEOUT",KR_TIMEOUT},
{"KR_BAN",KR_BAN},
{"KR_LEAVE",KR_LEAVE},
#endif
{NULL,0}
@ -8204,6 +8234,9 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"maptol")) {
lua_pushinteger(L, maptol);
return 1;
} else if (fastcmp(word,"ultimatemode")) {
lua_pushboolean(L, ultimatemode != 0);
return 1;
} else if (fastcmp(word,"mariomode")) {
lua_pushboolean(L, mariomode != 0);
return 1;
@ -8269,10 +8302,10 @@ static inline int lib_getenum(lua_State *L)
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
} else if (fastcmp(word,"admin")) {
if (!playeringame[adminplayer] || adminplayer == serverplayer)
} else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array.
if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer))
return 0;
LUA_PushUserdata(L, &players[adminplayer], META_PLAYER);
LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER);
return 1;
} else if (fastcmp(word,"emeralds")) {
lua_pushinteger(L, emeralds);

View File

@ -150,9 +150,9 @@ extern FILE *logstream;
// we use comprevision and compbranch instead.
#else
#define VERSION 201 // Game version
#define SUBVERSION 20 // more precise version number
#define VERSIONSTRING "v2.1.20"
#define VERSIONSTRINGW L"v2.1.20"
#define SUBVERSION 21 // more precise version number
#define VERSIONSTRING "v2.1.21"
#define VERSIONSTRINGW L"v2.1.21"
// Hey! If you change this, add 1 to the MODVERSION below!
// Otherwise we can't force updates!
#endif
@ -214,7 +214,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 25
#define MODVERSION 26
// =========================================================================

View File

@ -476,7 +476,8 @@ extern consvar_t cv_timetic; // display high resolution timer
extern consvar_t cv_forceskin; // force clients to use the server's skin
extern consvar_t cv_downloading; // allow clients to downloading WADs.
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
extern INT32 adminplayer, serverplayer;
extern INT32 serverplayer;
extern INT32 adminplayers[MAXPLAYERS];
/// \note put these in d_clisrv outright?

View File

@ -1739,7 +1739,7 @@ static void F_AdvanceToNextScene(void)
void F_EndCutScene(void)
{
cutsceneover = true; // do this first, just in case Y_EndGame or something wants to turn it back false later
cutsceneover = true; // do this first, just in case G_EndGame or something wants to turn it back false later
if (runningprecutscene)
{
if (server)
@ -1754,7 +1754,7 @@ void F_EndCutScene(void)
else if (nextmap < 1100-1)
G_NextLevel();
else
Y_EndGame();
G_EndGame();
}
}
@ -1858,7 +1858,7 @@ void F_CutsceneTicker(void)
for (i = 0; i < MAXPLAYERS; i++)
{
if (netgame && i != serverplayer && i != adminplayer)
if (netgame && i != serverplayer && !IsPlayerAdmin(i))
continue;
if (players[i].cmd.buttons & BT_USE)

View File

@ -350,11 +350,13 @@ static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"},
consvar_t cv_crosshair = {"crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_crosshair2 = {"crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_invertmouse = {"invertmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_alwaysfreelook = {"alwaysmlook", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_invertmouse2 = {"invertmouse2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_alwaysfreelook2 = {"alwaysmlook2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousemove = {"mousemove", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousemove2 = {"mousemove2", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_alwaysfreelook = {"alwaysmlook", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_alwaysfreelook2 = {"alwaysmlook2", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_chasefreelook = {"chasemlook", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_chasefreelook2 = {"chasemlook2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousemove = {"mousemove", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousemove2 = {"mousemove2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_analog = {"analog", "Off", CV_CALL, CV_OnOff, Analog_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_analog2 = {"analog2", "Off", CV_CALL, CV_OnOff, Analog2_OnChange, 0, NULL, NULL, 0, 0, NULL};
#ifdef DC
@ -385,7 +387,7 @@ consvar_t cv_lookaxis = {"joyaxis_look", "RStick.Y", CV_SAVE, joyaxis_cons_t, NU
consvar_t cv_fireaxis = {"joyaxis_fire", "LAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis = {"joyaxis_firenormal", "RAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#else
consvar_t cv_turnaxis = {"joyaxis_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis = {"joyaxis_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#ifdef PSP
consvar_t cv_moveaxis = {"joyaxis_move", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#else
@ -399,17 +401,17 @@ consvar_t cv_lookaxis = {"joyaxis_look", "Alt Y-Axis", CV_SAVE, joyaxis_cons_t,
#elif defined (PSP)
consvar_t cv_sideaxis = {"joyaxis_side", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#else
consvar_t cv_sideaxis = {"joyaxis_side", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_sideaxis = {"joyaxis_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
#ifndef _XBOX
#ifdef PSP
consvar_t cv_lookaxis = {"joyaxis_look", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#else
consvar_t cv_lookaxis = {"joyaxis_look", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookaxis = {"joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
#endif
consvar_t cv_fireaxis = {"joyaxis_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis = {"joyaxis_firenormal", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis = {"joyaxis_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis = {"joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
#if defined (_WII) || defined (WMINPUT)
@ -420,7 +422,7 @@ consvar_t cv_lookaxis2 = {"joyaxis2_look", "RStick.Y", CV_SAVE, joyaxis_cons_t,
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "LAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "RAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#else
consvar_t cv_turnaxis2 = {"joyaxis2_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis2 = {"joyaxis2_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_moveaxis2 = {"joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#ifdef _arch_dreamcast
consvar_t cv_sideaxis2 = {"joyaxis2_side", "Triggers", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -430,13 +432,13 @@ consvar_t cv_lookaxis2 = {"joyaxis2_look", "Alt Y-Axis", CV_SAVE, joyaxis_cons_t
#elif defined (_PSP)
consvar_t cv_sideaxis2 = {"joyaxis2_side", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#else
consvar_t cv_sideaxis2 = {"joyaxis2_side", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_sideaxis2 = {"joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
#ifndef _XBOX
consvar_t cv_lookaxis2 = {"joyaxis2_look", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookaxis2 = {"joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
@ -958,13 +960,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
INT32 tspeed, forward, side, axis, i;
const INT32 speed = 1;
// these ones used for multiple conditions
boolean turnleft, turnright, mouseaiming, analogjoystickmove, gamepadjoystickmove;
boolean turnleft, turnright, mouseaiming, analogjoystickmove, gamepadjoystickmove, thisjoyaiming;
player_t *player = &players[consoleplayer];
camera_t *thiscam = &camera;
static INT32 turnheld; // for accelerative turning
static boolean keyboard_look; // true if lookup/down using keyboard
static boolean resetdown; // don't cam reset every frame
static boolean joyaiming; // check the last frame's value if we need to reset the camera
G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver
@ -979,10 +982,18 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
turnright = PLAYER1INPUTDOWN(gc_turnright);
turnleft = PLAYER1INPUTDOWN(gc_turnleft);
mouseaiming = (PLAYER1INPUTDOWN(gc_mouseaiming)) ^ cv_alwaysfreelook.value;
mouseaiming = (PLAYER1INPUTDOWN(gc_mouseaiming)) ^
(cv_chasecam.value ? cv_chasefreelook.value : cv_alwaysfreelook.value);
analogjoystickmove = cv_usejoystick.value && !Joystick.bGamepadStyle;
gamepadjoystickmove = cv_usejoystick.value && Joystick.bGamepadStyle;
thisjoyaiming = (cv_chasecam.value) ? cv_chasefreelook.value : cv_alwaysfreelook.value;
// Reset the vertical look if we're no longer joyaiming
if (!thisjoyaiming && joyaiming)
localaiming = 0;
joyaiming = thisjoyaiming;
axis = JoyAxis(AXISTURN);
if (gamepadjoystickmove && axis != 0)
{
@ -1158,11 +1169,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics)
}
axis = JoyAxis(AXISLOOK);
if (analogjoystickmove && axis != 0 && cv_lookaxis.value != 0)
if (analogjoystickmove && joyaiming && axis != 0 && cv_lookaxis.value != 0)
localaiming += (axis<<16) * screen_invert;
// spring back if not using keyboard neither mouselookin'
if (!keyboard_look && cv_lookaxis.value == 0 && !mouseaiming)
if (!keyboard_look && cv_lookaxis.value == 0 && !joyaiming && !mouseaiming)
localaiming = 0;
if (PLAYER1INPUTDOWN(gc_lookup) || (gamepadjoystickmove && axis < 0))
@ -1249,13 +1260,14 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
INT32 tspeed, forward, side, axis, i;
const INT32 speed = 1;
// these ones used for multiple conditions
boolean turnleft, turnright, mouseaiming, analogjoystickmove, gamepadjoystickmove;
boolean turnleft, turnright, mouseaiming, analogjoystickmove, gamepadjoystickmove, thisjoyaiming;
player_t *player = &players[secondarydisplayplayer];
camera_t *thiscam = (player->bot == 2 ? &camera : &camera2);
static INT32 turnheld; // for accelerative turning
static boolean keyboard_look; // true if lookup/down using keyboard
static boolean resetdown; // don't cam reset every frame
static boolean joyaiming; // check the last frame's value if we need to reset the camera
G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver
@ -1270,10 +1282,18 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
turnright = PLAYER2INPUTDOWN(gc_turnright);
turnleft = PLAYER2INPUTDOWN(gc_turnleft);
mouseaiming = (PLAYER2INPUTDOWN(gc_mouseaiming)) ^ cv_alwaysfreelook2.value;
mouseaiming = (PLAYER2INPUTDOWN(gc_mouseaiming)) ^
(cv_chasecam2.value ? cv_chasefreelook2.value : cv_alwaysfreelook2.value);
analogjoystickmove = cv_usejoystick2.value && !Joystick2.bGamepadStyle;
gamepadjoystickmove = cv_usejoystick2.value && Joystick2.bGamepadStyle;
thisjoyaiming = (cv_chasecam2.value) ? cv_chasefreelook2.value : cv_alwaysfreelook2.value;
// Reset the vertical look if we're no longer joyaiming
if (!thisjoyaiming && joyaiming)
localaiming2 = 0;
joyaiming = thisjoyaiming;
axis = Joy2Axis(AXISTURN);
if (gamepadjoystickmove && axis != 0)
{
@ -1446,11 +1466,11 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics)
}
axis = Joy2Axis(AXISLOOK);
if (analogjoystickmove && axis != 0 && cv_lookaxis2.value != 0)
if (analogjoystickmove && joyaiming && axis != 0 && cv_lookaxis2.value != 0)
localaiming2 += (axis<<16) * screen_invert;
// spring back if not using keyboard neither mouselookin'
if (!keyboard_look && cv_lookaxis2.value == 0 && !mouseaiming)
if (!keyboard_look && cv_lookaxis2.value == 0 && !joyaiming && !mouseaiming)
localaiming2 = 0;
if (PLAYER2INPUTDOWN(gc_lookup) || (gamepadjoystickmove && axis < 0))
@ -1673,7 +1693,8 @@ static INT32 camtoggledelay, camtoggledelay2 = 0;
boolean G_Responder(event_t *ev)
{
// allow spy mode changes even during the demo
if (gamestate == GS_LEVEL && ev->type == ev_keydown && ev->data1 == KEY_F12)
if (gamestate == GS_LEVEL && ev->type == ev_keydown
&& (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1]))
{
if (splitscreen || !netgame)
displayplayer = consoleplayer;
@ -1814,7 +1835,8 @@ boolean G_Responder(event_t *ev)
{
case ev_keydown:
if (ev->data1 == gamecontrol[gc_pause][0]
|| ev->data1 == gamecontrol[gc_pause][1])
|| ev->data1 == gamecontrol[gc_pause][1]
|| ev->data1 == KEY_PAUSE)
{
if (!pausedelay)
{
@ -2547,14 +2569,12 @@ void G_DoReborn(INT32 playernum)
}
}
else
#ifdef HAVE_BLUA
{
LUAh_MapChange();
#ifdef HAVE_BLUA
LUAh_MapChange(gamemap);
#endif
G_DoLoadLevel(true);
#ifdef HAVE_BLUA
}
#endif
}
else
{
@ -2605,7 +2625,7 @@ void G_ExitLevel(void)
CONS_Printf(M_GetText("The round has ended.\n"));
// Remove CEcho text on round end.
HU_DoCEcho("");
HU_ClearCEcho();
}
}
@ -2901,7 +2921,7 @@ void G_AfterIntermission(void)
if (nextmap < 1100-1)
G_NextLevel();
else
Y_EndGame();
G_EndGame();
}
}
@ -2987,6 +3007,38 @@ static void G_DoContinued(void)
gameaction = ga_nothing;
}
//
// G_EndGame (formerly Y_EndGame)
// Frankly this function fits better in g_game.c than it does in y_inter.c
//
// ...Gee, (why) end the game?
// Because G_AfterIntermission and F_EndCutscene would
// both do this exact same thing *in different ways* otherwise,
// which made it so that you could only unlock Ultimate mode
// if you had a cutscene after the final level and crap like that.
// This function simplifies it so only one place has to be updated
// when something new is added.
void G_EndGame(void)
{
// Only do evaluation and credits in coop games.
if (gametype == GT_COOP)
{
if (nextmap == 1102-1) // end game with credits
{
F_StartCredits();
return;
}
if (nextmap == 1101-1) // end game with evaluation
{
F_StartGameEvaluation();
return;
}
}
// 1100 or competitive multiplayer, so go back to title screen.
D_StartTitle();
}
//
// G_LoadGameSettings
//
@ -5091,7 +5143,7 @@ void G_DoPlayDemo(char *defdemoname)
demo_start = false;
#ifdef HAVE_BLUA
LUAh_MapChange();
LUAh_MapChange(gamemap);
#endif
displayplayer = consoleplayer = 0;
memset(playeringame,0,sizeof(playeringame));

View File

@ -55,8 +55,8 @@ extern INT16 rw_maximums[NUM_WEAPONS];
// used in game menu
extern consvar_t cv_crosshair, cv_crosshair2;
extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_mousemove;
extern consvar_t cv_invertmouse2, cv_alwaysfreelook2, cv_mousemove2;
extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_chasefreelook, cv_mousemove;
extern consvar_t cv_invertmouse2, cv_alwaysfreelook2, cv_chasefreelook2, cv_mousemove2;
extern consvar_t cv_useranalog, cv_useranalog2;
extern consvar_t cv_analog, cv_analog2;
extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_fireaxis,cv_firenaxis;
@ -174,6 +174,7 @@ void G_NextLevel(void);
void G_Continue(void);
void G_UseContinue(void);
void G_AfterIntermission(void);
void G_EndGame(void); // moved from y_inter.c/h and renamed
void G_Ticker(boolean run);
boolean G_Responder(event_t *ev);

View File

@ -25,10 +25,10 @@ static CV_PossibleValue_t mousesens_cons_t[] = {{1, "MIN"}, {MAXMOUSESENSITIVITY
static CV_PossibleValue_t onecontrolperkey_cons_t[] = {{1, "One"}, {2, "Several"}, {0, NULL}};
// mouse values are used once
consvar_t cv_mousesens = {"mousesens", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousesens2 = {"mousesens2", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mouseysens = {"mouseysens", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mouseysens2 = {"mouseysens2", "35", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousesens = {"mousesens", "20", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousesens2 = {"mousesens2", "20", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mouseysens = {"mouseysens", "20", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mouseysens2 = {"mouseysens2", "20", CV_SAVE, mousesens_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_controlperkey = {"controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
INT32 mousex, mousey;
@ -990,6 +990,10 @@ static const char *gamecontrolname[num_gamecontrols] =
"jump",
"console",
"pause",
"systemmenu",
"screenshot",
"recordgif",
"viewpoint",
"custom1",
"custom2",
"custom3",
@ -1154,10 +1158,8 @@ void G_Controldefault(void)
#else
void G_Controldefault(void)
{
gamecontrol[gc_forward ][0] = KEY_UPARROW;
gamecontrol[gc_forward ][1] = 'w';
gamecontrol[gc_backward ][0] = KEY_DOWNARROW;
gamecontrol[gc_backward ][1] = 's';
gamecontrol[gc_forward ][0] = 'w';
gamecontrol[gc_backward ][0] = 's';
gamecontrol[gc_strafeleft ][0] = 'a';
gamecontrol[gc_straferight][0] = 'd';
gamecontrol[gc_turnleft ][0] = KEY_LEFTARROW;
@ -1178,21 +1180,24 @@ void G_Controldefault(void)
gamecontrol[gc_fire ][1] = KEY_MOUSE1+0;
gamecontrol[gc_firenormal ][0] = 'c';
gamecontrol[gc_tossflag ][0] = '\'';
gamecontrol[gc_use ][0] = 'x';
gamecontrol[gc_use ][0] = KEY_LSHIFT;
gamecontrol[gc_camtoggle ][0] = 'v';
gamecontrol[gc_camleft ][0] = '[';
gamecontrol[gc_camright ][0] = ']';
gamecontrol[gc_camreset ][0] = 'r';
gamecontrol[gc_lookup ][0] = KEY_PGUP;
gamecontrol[gc_lookdown ][0] = KEY_PGDN;
gamecontrol[gc_lookup ][0] = KEY_UPARROW;
gamecontrol[gc_lookdown ][0] = KEY_DOWNARROW;
gamecontrol[gc_centerview ][0] = KEY_END;
gamecontrol[gc_talkkey ][0] = 't';
gamecontrol[gc_teamkey ][0] = 'y';
gamecontrol[gc_scores ][0] = KEY_TAB;
gamecontrol[gc_jump ][0] = 'z';
gamecontrol[gc_jump ][1] = KEY_MOUSE1+1;
gamecontrol[gc_jump ][0] = KEY_SPACE;
gamecontrol[gc_console ][0] = KEY_CONSOLE;
gamecontrol[gc_pause ][0] = KEY_PAUSE;
gamecontrol[gc_pause ][0] = 'p';
gamecontrol[gc_screenshot ][0] = KEY_F8;
gamecontrol[gc_recordgif ][0] = KEY_F9;
gamecontrol[gc_viewpoint ][0] = KEY_F12;
gamecontrol[gc_systemmenu ][0] = KEY_JOY1+7; // Start
#ifdef WMINPUT
gamecontrol[gc_forward ][0] = KEY_JOY1+02; //UP
gamecontrol[gc_backward ][0] = KEY_JOY1+03; //DOWN
@ -1330,11 +1335,31 @@ static void setcontrol(INT32 (*gc)[2], INT32 na)
return;
}
keynum = G_KeyStringtoNum(COM_Argv(2));
if (keynum == KEY_PAUSE) // fail silently; pause is hardcoded
{
if (na == 4)
{
na--;
keynum = G_KeyStringtoNum(COM_Argv(3));
if (keynum == KEY_PAUSE)
return;
}
else
return;
}
G_CheckDoubleUsage(keynum);
gc[numctrl][0] = keynum;
if (na == 4)
gc[numctrl][1] = G_KeyStringtoNum(COM_Argv(3));
{
keynum = G_KeyStringtoNum(COM_Argv(3));
if (keynum != KEY_PAUSE)
gc[numctrl][1] = keynum;
else
gc[numctrl][1] = 0;
}
else
gc[numctrl][1] = 0;
}

View File

@ -118,6 +118,10 @@ typedef enum
gc_jump,
gc_console,
gc_pause,
gc_systemmenu,
gc_screenshot,
gc_recordgif,
gc_viewpoint,
gc_custom1, // Lua scriptable
gc_custom2, // Lua scriptable
gc_custom3, // Lua scriptable

View File

@ -347,14 +347,14 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags)
numwords = COM_Argc() - usedargs;
I_Assert(numwords > 0);
if (cv_mute.value && !(server || adminplayer == consoleplayer))
if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
{
CONS_Alert(CONS_NOTICE, M_GetText("The chat is muted. You can't say anything at the moment.\n"));
return;
}
// Only servers/admins can CSAY.
if(!server && adminplayer != consoleplayer)
if(!server && IsPlayerAdmin(consoleplayer))
flags &= ~HU_CSAY;
// We handle HU_SERVER_SAY, not the caller.
@ -448,7 +448,7 @@ static void Command_CSay_f(void)
return;
}
if(!server && adminplayer != consoleplayer)
if(!server && !IsPlayerAdmin(consoleplayer))
{
CONS_Alert(CONS_NOTICE, M_GetText("Only servers and admins can use csay.\n"));
return;
@ -477,7 +477,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
msg = (char *)*p;
SKIPSTRING(*p);
if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && playernum != adminplayer)
if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !IsPlayerAdmin(playernum))
{
CONS_Alert(CONS_WARNING, cv_mute.value ?
M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"),
@ -575,7 +575,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
// Give admins and remote admins their symbols.
if (playernum == serverplayer)
tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(adminchar) + 1, PU_STATIC, NULL);
else if (playernum == adminplayer)
else if (IsPlayerAdmin(playernum))
tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(remotechar) + 1, PU_STATIC, NULL);
if (tempchar)
{
@ -710,7 +710,7 @@ static void HU_queueChatChar(char c)
} while (c);
// last minute mute check
if (cv_mute.value && !(server || adminplayer == consoleplayer))
if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
{
CONS_Alert(CONS_NOTICE, M_GetText("The chat is muted. You can't say anything at the moment.\n"));
return;
@ -768,9 +768,9 @@ boolean HU_Responder(event_t *ev)
{
// enter chat mode
if ((ev->data1 == gamecontrol[gc_talkkey][0] || ev->data1 == gamecontrol[gc_talkkey][1])
&& netgame && (!cv_mute.value || server || (adminplayer == consoleplayer)))
&& netgame && (!cv_mute.value || server || IsPlayerAdmin(consoleplayer)))
{
if (cv_mute.value && !(server || adminplayer == consoleplayer))
if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
return false;
chat_on = true;
w_chat[0] = 0;
@ -778,9 +778,9 @@ boolean HU_Responder(event_t *ev)
return true;
}
if ((ev->data1 == gamecontrol[gc_teamkey][0] || ev->data1 == gamecontrol[gc_teamkey][1])
&& netgame && (!cv_mute.value || server || (adminplayer == consoleplayer)))
&& netgame && (!cv_mute.value || server || (IsPlayerAdmin(consoleplayer))))
{
if (cv_mute.value && !(server || adminplayer == consoleplayer))
if (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer)))
return false;
chat_on = true;
w_chat[0] = 0;

View File

@ -713,14 +713,29 @@ static boolean SOCK_CanGet(void)
#endif
#ifndef NONET
static void SOCK_Send(void)
static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr)
{
ssize_t c = ERRSOCKET;
socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in);
#ifdef HAVE_IPV6
socklen_t d6 = (socklen_t)sizeof(struct sockaddr_in6);
#endif
socklen_t d, da = (socklen_t)sizeof(mysockaddr_t);
switch (sockaddr->any.sa_family)
{
case AF_INET: d = d4; break;
#ifdef HAVE_IPV6
case AF_INET6: d = d6; break;
#endif
default: d = da; break;
}
return sendto(socket, (char *)&doomcom->data, doomcom->datalength, 0, &sockaddr->any, d);
}
static void SOCK_Send(void)
{
ssize_t c = ERRSOCKET;
size_t i, j;
if (!nodeconnected[doomcom->remotenode])
@ -733,19 +748,7 @@ static void SOCK_Send(void)
for (j = 0; j < broadcastaddresses; j++)
{
if (myfamily[i] == broadcastaddress[j].any.sa_family)
{
if (broadcastaddress[i].any.sa_family == AF_INET)
d = d4;
#ifdef HAVE_IPV6
else if (broadcastaddress[i].any.sa_family == AF_INET6)
d = d6;
#endif
else
d = da;
c = sendto(mysockets[i], (char *)&doomcom->data, doomcom->datalength, 0,
&broadcastaddress[j].any, d);
}
SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]);
}
}
return;
@ -755,35 +758,13 @@ static void SOCK_Send(void)
for (i = 0; i < mysocketses; i++)
{
if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family)
{
if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET)
d = d4;
#ifdef HAVE_IPV6
else if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET6)
d = d6;
#endif
else
d = da;
sendto(mysockets[i], (char *)&doomcom->data, doomcom->datalength, 0,
&clientaddress[doomcom->remotenode].any, d);
}
SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]);
}
return;
}
else
{
if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET)
d = d4;
#ifdef HAVE_IPV6
else if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET6)
d = d6;
#endif
else
d = da;
c = sendto(nodesocket[doomcom->remotenode], (char *)&doomcom->data, doomcom->datalength, 0,
&clientaddress[doomcom->remotenode].any, d);
c = SOCK_SendToAddr(nodesocket[doomcom->remotenode], &clientaddress[doomcom->remotenode]);
}
if (c == ERRSOCKET)
@ -1075,7 +1056,7 @@ static boolean UDP_Socket(void)
if (gaie == 0)
{
runp = ai;
while (runp != NULL)
while (runp != NULL && s < MAXNETNODES+1)
{
memcpy(&clientaddress[s], runp->ai_addr, runp->ai_addrlen);
s++;
@ -1090,12 +1071,15 @@ static boolean UDP_Socket(void)
clientaddress[s].ip4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); //GetLocalAddress(); // my own ip
s++;
}
s = 0;
// setup broadcast adress to BROADCASTADDR entry
gaie = I_getaddrinfo("255.255.255.255", "0", &hints, &ai);
if (gaie == 0)
{
runp = ai;
while (runp != NULL)
while (runp != NULL && s < MAXNETNODES+1)
{
memcpy(&broadcastaddress[s], runp->ai_addr, runp->ai_addrlen);
s++;
@ -1118,7 +1102,7 @@ static boolean UDP_Socket(void)
if (gaie == 0)
{
runp = ai;
while (runp != NULL)
while (runp != NULL && s < MAXNETNODES+1)
{
memcpy(&broadcastaddress[s], runp->ai_addr, runp->ai_addrlen);
s++;

View File

@ -12733,7 +12733,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
10, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
S_NULL // raisestate
},

View File

@ -3629,7 +3629,7 @@ msgid "another castle!"
msgstr ""
#: st_stuff.c:2328 st_stuff.c:2334 st_stuff.c:2356
msgid "Press F12 to watch another player."
msgid "Press Viewpoint Key to watch a player."
msgstr ""
#: st_stuff.c:2333

View File

@ -3820,7 +3820,7 @@ msgid "another castle!"
msgstr ""
#: st_stuff.c:2092 st_stuff.c:2098 st_stuff.c:2120
msgid "Press F12 to watch another player."
msgid "Press Viewpoint Key to watch a player."
msgstr ""
#: st_stuff.c:2097

View File

@ -14,12 +14,18 @@
#ifdef HAVE_BLUA
#include "p_local.h"
#include "p_setup.h" // So we can have P_SetupLevelSky
#ifdef ESLOPE
#include "p_slopes.h" // P_GetZAt
#endif
#include "z_zone.h"
#include "r_main.h"
#include "r_things.h"
#include "m_random.h"
#include "s_sound.h"
#include "g_game.h"
#include "hu_stuff.h"
#include "console.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "lua_script.h"
#include "lua_libs.h"
@ -93,6 +99,16 @@ static int lib_evalMath(lua_State *L)
return 1;
}
static int lib_isPlayerAdmin(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, IsPlayerAdmin(player-players));
return 1;
}
// M_RANDOM
//////////////
@ -1547,6 +1563,24 @@ static int lib_evCrumbleChain(lua_State *L)
return 0;
}
#ifdef ESLOPE
// P_SLOPES
////////////
static int lib_pGetZAt(lua_State *L)
{
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
//HUDSAFE
if (!slope)
return LUA_ErrInvalid(L, "pslope_t");
lua_pushfixed(L, P_GetZAt(slope, x, y));
return 1;
}
#endif
// R_DEFS
////////////
@ -1983,6 +2017,7 @@ static int lib_gTicsToMilliseconds(lua_State *L)
static luaL_Reg lib[] = {
{"print", lib_print},
{"EvalMath", lib_evalMath},
{"IsPlayerAdmin", lib_isPlayerAdmin},
// m_random
{"P_RandomFixed",lib_pRandomFixed},
@ -2113,6 +2148,11 @@ static luaL_Reg lib[] = {
{"P_StartQuake",lib_pStartQuake},
{"EV_CrumbleChain",lib_evCrumbleChain},
#ifdef ESLOPE
// p_slopes
{"P_GetZAt",lib_pGetZAt},
#endif
// r_defs
{"R_PointToAngle",lib_rPointToAngle},
{"R_PointToAngle2",lib_rPointToAngle2},

266
src/lua_blockmaplib.c Normal file
View File

@ -0,0 +1,266 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2016 by Iestyn "Monster Iestyn" Jealous.
// Copyright (C) 2016 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file lua_blockmaplib.c
/// \brief blockmap library for Lua scripting
#include "doomdef.h"
#ifdef HAVE_BLUA
#include "p_local.h"
#include "r_main.h" // validcount
#include "lua_script.h"
#include "lua_libs.h"
//#include "lua_hud.h" // hud_running errors
static const char *const search_opt[] = {
"objects",
"lines",
NULL};
// a quickly-made function pointer typedef used by lib_searchBlockmap...
// return values:
// 0 - normal, no interruptions
// 1 - stop search through current block
// 2 - stop search completely
typedef UINT8 (*blockmap_func)(lua_State *, INT32, INT32, mobj_t *);
static boolean blockfuncerror = false; // errors should only print once per search blockmap call
// Helper function for "objects" search
static UINT8 lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
{
mobj_t *mobj, *bnext = NULL;
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
return 0;
// Check interaction with the objects in the blockmap.
for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = bnext)
{
P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed!
if (mobj == thing)
continue; // our thing just found itself, so move on
lua_pushvalue(L, 1); // push function
LUA_PushUserdata(L, thing, META_MOBJ);
LUA_PushUserdata(L, mobj, META_MOBJ);
if (lua_pcall(gL, 2, 1, 0)) {
if (!blockfuncerror || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
blockfuncerror = true;
return 0; // *shrugs*
}
if (!lua_isnil(gL, -1))
{ // if nil, continue
if (lua_toboolean(gL, -1))
return 2; // stop whole search
else
return 1; // stop block search
}
lua_pop(gL, 1);
if (P_MobjWasRemoved(thing) // func just popped our thing, cannot continue.
|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
{
P_SetTarget(&bnext, NULL);
return (P_MobjWasRemoved(thing)) ? 2 : 1;
}
}
return 0;
}
// Helper function for "lines" search
static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
{
INT32 offset;
const INT32 *list; // Big blockmap
#ifdef POLYOBJECTS
polymaplink_t *plink; // haleyjd 02/22/06
#endif
line_t *ld;
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
return 0;
offset = y*bmapwidth + x;
#ifdef POLYOBJECTS
// haleyjd 02/22/06: consider polyobject lines
plink = polyblocklinks[offset];
while (plink)
{
polyobj_t *po = plink->po;
if (po->validcount != validcount) // if polyobj hasn't been checked
{
size_t i;
po->validcount = validcount;
for (i = 0; i < po->numLines; ++i)
{
if (po->lines[i]->validcount == validcount) // line has been checked
continue;
po->lines[i]->validcount = validcount;
lua_pushvalue(L, 1);
LUA_PushUserdata(L, thing, META_MOBJ);
LUA_PushUserdata(L, po->lines[i], META_LINE);
if (lua_pcall(gL, 2, 1, 0)) {
if (!blockfuncerror || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
blockfuncerror = true;
return 0; // *shrugs*
}
if (!lua_isnil(gL, -1))
{ // if nil, continue
if (lua_toboolean(gL, -1))
return 2; // stop whole search
else
return 1; // stop block search
}
lua_pop(gL, 1);
if (P_MobjWasRemoved(thing))
return 2;
}
}
plink = (polymaplink_t *)(plink->link.next);
}
#endif
offset = *(blockmap + offset); // offset = blockmap[y*bmapwidth+x];
// First index is really empty, so +1 it.
for (list = blockmaplump + offset + 1; *list != -1; list++)
{
ld = &lines[*list];
if (ld->validcount == validcount)
continue; // Line has already been checked.
ld->validcount = validcount;
lua_pushvalue(L, 1);
LUA_PushUserdata(L, thing, META_MOBJ);
LUA_PushUserdata(L, ld, META_LINE);
if (lua_pcall(gL, 2, 1, 0)) {
if (!blockfuncerror || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
blockfuncerror = true;
return 0; // *shrugs*
}
if (!lua_isnil(gL, -1))
{ // if nil, continue
if (lua_toboolean(gL, -1))
return 2; // stop whole search
else
return 1; // stop block search
}
lua_pop(gL, 1);
if (P_MobjWasRemoved(thing))
return 2;
}
return 0; // Everything was checked.
}
// The searchBlockmap function
// arguments: searchBlockmap(searchtype, function, mobj, [x1, x2, y1, y2])
// return value:
// true = search completely uninteruppted,
// false = searching of at least one block stopped mid-way (including if the whole search was stopped)
static int lib_searchBlockmap(lua_State *L)
{
int searchtype = luaL_checkoption(L, 1, "objects", search_opt);
int n;
mobj_t *mobj;
INT32 xl, xh, yl, yh, bx, by;
fixed_t x1, x2, y1, y2;
boolean retval = true;
UINT8 funcret = 0;
blockmap_func searchFunc;
lua_remove(L, 1); // remove searchtype, stack is now function, mobj, [x1, x2, y1, y2]
luaL_checktype(L, 1, LUA_TFUNCTION);
switch (searchtype)
{
case 0: // "objects"
default:
searchFunc = lib_searchBlockmap_Objects;
break;
case 1: // "lines"
searchFunc = lib_searchBlockmap_Lines;
break;
}
// the mobj we are searching around, the "calling" mobj we could say
mobj = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
n = lua_gettop(L);
if (n > 2) // specific x/y ranges have been supplied
{
if (n < 6)
return luaL_error(L, "arguments 4 to 6 not all given (expected 4 fixed-point integers)");
x1 = luaL_checkfixed(L, 3);
x2 = luaL_checkfixed(L, 4);
y1 = luaL_checkfixed(L, 5);
y2 = luaL_checkfixed(L, 6);
}
else // mobj and function only - search around mobj's radius by default
{
fixed_t radius = mobj->radius + MAXRADIUS;
x1 = mobj->x - radius;
x2 = mobj->x + radius;
y1 = mobj->y - radius;
y2 = mobj->y + radius;
}
lua_settop(L, 2); // pop everything except function, mobj
xl = (unsigned)(x1 - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(x2 - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(y1 - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(y2 - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
blockfuncerror = false; // reset
validcount++;
for (bx = xl; bx <= xh; bx++)
for (by = yl; by <= yh; by++)
{
funcret = searchFunc(L, bx, by, mobj);
// return value of searchFunc determines searchFunc's return value and/or when to stop
if (funcret == 2){ // stop whole search
lua_pushboolean(L, false); // return false
return 1;
}
else if (funcret == 1) // search was interrupted for this block
retval = false; // this changes the return value, but doesn't stop the whole search
// else don't do anything, continue as normal
if (P_MobjWasRemoved(mobj)){ // ...unless the original object was removed
lua_pushboolean(L, false); // in which case we have to stop now regardless
return 1;
}
}
lua_pushboolean(L, retval);
return 1;
}
int LUA_BlockmapLib(lua_State *L)
{
lua_register(L, "searchBlockmap", lib_searchBlockmap);
return 0;
}
#endif

View File

@ -55,7 +55,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum)
lua_pop(gL, 1); // pop flags
// requires server/admin and the player is not one of them
if ((flags & 1) && playernum != serverplayer && playernum != adminplayer)
if ((flags & 1) && playernum != serverplayer && !IsPlayerAdmin(playernum))
goto deny;
lua_rawgeti(gL, -1, 1); // push function from command info table
@ -133,7 +133,7 @@ void COM_Lua_f(void)
UINT8 argc;
lua_pop(gL, 1); // pop command info table
if (flags & 1 && !server && adminplayer != playernum) // flag 1: only server/admin can use this command.
if (flags & 1 && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command.
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;

View File

@ -43,12 +43,13 @@ enum hook {
hook_PlayerMsg,
hook_HurtMsg,
hook_PlayerSpawn,
hook_PlayerQuit,
hook_MAX // last hook
};
extern const char *const hookNames[];
void LUAh_MapChange(void); // Hook for map change (before load)
void LUAh_MapChange(INT16 mapnumber); // Hook for map change (before load)
void LUAh_MapLoad(void); // Hook for map load
void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer
void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers)
@ -77,5 +78,6 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook
boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages
boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages
#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer
void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting
#endif

View File

@ -54,6 +54,7 @@ const char *const hookNames[hook_MAX+1] = {
"PlayerMsg",
"HurtMsg",
"PlayerSpawn",
"PlayerQuit",
NULL
};
@ -314,14 +315,14 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which)
}
// Hook for map change (before load)
void LUAh_MapChange(void)
void LUAh_MapChange(INT16 mapnumber)
{
hook_p hookp;
if (!gL || !(hooksAvailable[hook_MapChange/8] & (1<<(hook_MapChange%8))))
return;
lua_settop(gL, 0);
lua_pushinteger(gL, gamemap);
lua_pushinteger(gL, mapnumber);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_MapChange)
@ -1074,4 +1075,30 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc)
// stack: tables
}
void LUAh_PlayerQuit(player_t *plr, int reason)
{
hook_p hookp;
if (!gL || !(hooksAvailable[hook_PlayerQuit/8] & (1<<(hook_PlayerQuit%8))))
return;
lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_PlayerQuit)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit
lua_pushinteger(gL, reason); // Reason for quitting
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
LUA_Call(gL, 2);
}
lua_settop(gL, 0);
}
#endif

View File

@ -560,6 +560,15 @@ static int libd_renderer(lua_State *L)
return 1;
}
// 30/10/18 Lat': Get cv_translucenthud's value for HUD rendering as a normal V_xxTRANS int
// Could as well be thrown in global vars for ease of access but I guess it makes sense for it to be a HUD fn
static int libd_getlocaltransflag(lua_State *L)
{
HUDONLY
lua_pushinteger(L, (10-cv_translucenthud.value)*V_10TRANS); // A bit weird that it's called "translucenthud" yet 10 is fully opaque :V
return 1;
}
static luaL_Reg lib_draw[] = {
{"patchExists", libd_patchExists},
{"cachePatch", libd_cachePatch},
@ -576,6 +585,7 @@ static luaL_Reg lib_draw[] = {
{"dupx", libd_dupx},
{"dupy", libd_dupy},
{"renderer", libd_renderer},
{"localTransFlag", libd_getlocaltransflag},
{NULL, NULL}
};
@ -599,6 +609,19 @@ static int lib_huddisable(lua_State *L)
return 0;
}
// 30/10/18: Lat': How come this wasn't here before?
static int lib_hudenabled(lua_State *L)
{
enum hud option = luaL_checkoption(L, 1, NULL, hud_disable_options);
if (hud_enabled[option/8] & (1<<(option%8)))
lua_pushboolean(L, true);
else
lua_pushboolean(L, false);
return 1;
}
// add a HUD element for rendering
static int lib_hudadd(lua_State *L)
{
@ -623,6 +646,7 @@ static int lib_hudadd(lua_State *L)
static luaL_Reg lib_hud[] = {
{"enable", lib_hudenable},
{"disable", lib_huddisable},
{"enabled", lib_hudenabled},
{"add", lib_hudadd},
{NULL, NULL}
};

View File

@ -38,6 +38,11 @@ extern lua_State *gL;
#define META_SUBSECTOR "SUBSECTOR_T*"
#define META_SECTOR "SECTOR_T*"
#define META_FFLOOR "FFLOOR_T*"
#ifdef ESLOPE
#define META_SLOPE "PSLOPE_T*"
#define META_VECTOR2 "VECTOR2_T"
#define META_VECTOR3 "VECTOR3_T"
#endif
#define META_MAPHEADER "MAPHEADER_T*"
#define META_CVAR "CONSVAR_T*"
@ -64,6 +69,7 @@ int LUA_PlayerLib(lua_State *L);
int LUA_SkinLib(lua_State *L);
int LUA_ThinkerLib(lua_State *L);
int LUA_MapLib(lua_State *L);
int LUA_BlockmapLib(lua_State *L);
int LUA_HudLib(lua_State *L);
#endif

View File

@ -16,6 +16,10 @@
#include "p_local.h"
#include "p_setup.h"
#include "z_zone.h"
#ifdef ESLOPE
#include "p_slopes.h"
#endif
#include "r_main.h"
#include "lua_script.h"
#include "lua_libs.h"
@ -38,7 +42,13 @@ enum sector_e {
sector_heightsec,
sector_camsec,
sector_lines,
#ifdef ESLOPE
sector_ffloors,
sector_fslope,
sector_cslope
#else
sector_ffloors
#endif
};
static const char *const sector_opt[] = {
@ -55,6 +65,10 @@ static const char *const sector_opt[] = {
"camsec",
"lines",
"ffloors",
#ifdef ESLOPE
"f_slope",
"c_slope",
#endif
NULL};
enum subsector_e {
@ -160,6 +174,10 @@ enum ffloor_e {
ffloor_toplightlevel,
ffloor_bottomheight,
ffloor_bottompic,
#ifdef ESLOPE
ffloor_tslope,
ffloor_bslope,
#endif
ffloor_sector,
ffloor_flags,
ffloor_master,
@ -176,6 +194,10 @@ static const char *const ffloor_opt[] = {
"toplightlevel",
"bottomheight",
"bottompic",
#ifdef ESLOPE
"t_slope",
"b_slope",
#endif
"sector", // secnum pushed as control sector userdata
"flags",
"master", // control linedef
@ -185,6 +207,47 @@ static const char *const ffloor_opt[] = {
"alpha",
NULL};
#ifdef ESLOPE
enum slope_e {
slope_valid = 0,
slope_o,
slope_d,
slope_zdelta,
slope_normal,
slope_zangle,
slope_xydirection,
slope_sourceline,
slope_refpos,
slope_flags
};
static const char *const slope_opt[] = {
"valid",
"o",
"d",
"zdelta",
"normal",
"zangle",
"xydirection",
"sourceline",
"refpos",
"flags",
NULL};
// shared by both vector2_t and vector3_t
enum vector_e {
vector_x = 0,
vector_y,
vector_z
};
static const char *const vector_opt[] = {
"x",
"y",
"z",
NULL};
#endif
static const char *const array_opt[] ={"iterate",NULL};
static const char *const valid_opt[] ={"valid",NULL};
@ -327,6 +390,7 @@ static int sector_get(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt);
INT16 i;
if (!sector)
{
@ -349,11 +413,23 @@ static int sector_get(lua_State *L)
lua_pushfixed(L, sector->ceilingheight);
return 1;
case sector_floorpic: // floorpic
lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
{
levelflat_t *levelflat = &levelflats[sector->floorpic];
for (i = 0; i < 8; i++)
if (!levelflat->name[i])
break;
lua_pushlstring(L, levelflat->name, i);
return 1;
}
case sector_ceilingpic: // ceilingpic
lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
{
levelflat_t *levelflat = &levelflats[sector->ceilingpic];
for (i = 0; i < 8; i++)
if (!levelflat->name[i])
break;
lua_pushlstring(L, levelflat->name, i);
return 1;
}
case sector_lightlevel:
lua_pushinteger(L, sector->lightlevel);
return 1;
@ -386,6 +462,14 @@ static int sector_get(lua_State *L)
LUA_PushUserdata(L, sector->ffloors, META_FFLOOR);
lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateFFloors and sector->ffloors as upvalues for the function
return 1;
#ifdef ESLOPE
case sector_fslope: // f_slope
LUA_PushUserdata(L, sector->f_slope, META_SLOPE);
return 1;
case sector_cslope: // c_slope
LUA_PushUserdata(L, sector->c_slope, META_SLOPE);
return 1;
#endif
}
return 0;
}
@ -408,6 +492,10 @@ static int sector_set(lua_State *L)
case sector_heightsec: // heightsec
case sector_camsec: // camsec
case sector_ffloors: // ffloors
#ifdef ESLOPE
case sector_fslope: // f_slope
case sector_cslope: // c_slope
#endif
default:
return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]);
case sector_floorheight: { // floorheight
@ -1042,6 +1130,14 @@ static int ffloor_get(lua_State *L)
lua_pushlstring(L, levelflat->name, 8);
return 1;
}
#ifdef ESLOPE
case ffloor_tslope:
LUA_PushUserdata(L, *ffloor->t_slope, META_SLOPE);
return 1;
case ffloor_bslope:
LUA_PushUserdata(L, *ffloor->b_slope, META_SLOPE);
return 1;
#endif
case ffloor_sector:
LUA_PushUserdata(L, &sectors[ffloor->secnum], META_SECTOR);
return 1;
@ -1081,6 +1177,10 @@ static int ffloor_set(lua_State *L)
switch(field)
{
case ffloor_valid: // valid
#ifdef ESLOPE
case ffloor_tslope: // t_slope
case ffloor_bslope: // b_slope
#endif
case ffloor_sector: // sector
case ffloor_master: // master
case ffloor_target: // target
@ -1141,6 +1241,181 @@ static int ffloor_set(lua_State *L)
return 0;
}
#ifdef ESLOPE
static int slope_get(lua_State *L)
{
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt);
if (!slope)
{
if (field == slope_valid) {
lua_pushboolean(L, 0);
return 1;
}
return luaL_error(L, "accessed pslope_t doesn't exist anymore.");
}
switch(field)
{
case slope_valid: // valid
lua_pushboolean(L, 1);
return 1;
case slope_o: // o
LUA_PushUserdata(L, &slope->o, META_VECTOR3);
return 1;
case slope_d: // d
LUA_PushUserdata(L, &slope->d, META_VECTOR2);
return 1;
case slope_zdelta: // zdelta
lua_pushfixed(L, slope->zdelta);
return 1;
case slope_normal: // normal
LUA_PushUserdata(L, &slope->normal, META_VECTOR3);
return 1;
case slope_zangle: // zangle
lua_pushangle(L, slope->zangle);
return 1;
case slope_xydirection: // xydirection
lua_pushangle(L, slope->xydirection);
return 1;
case slope_sourceline: // source linedef
LUA_PushUserdata(L, slope->sourceline, META_LINE);
return 1;
case slope_refpos: // refpos
lua_pushinteger(L, slope->refpos);
return 1;
case slope_flags: // flags
lua_pushinteger(L, slope->flags);
return 1;
}
return 0;
}
static int slope_set(lua_State *L)
{
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt);
if (!slope)
return luaL_error(L, "accessed pslope_t doesn't exist anymore.");
if (hud_running)
return luaL_error(L, "Do not alter pslope_t in HUD rendering code!");
switch(field) // todo: reorganize this shit
{
case slope_valid: // valid
case slope_sourceline: // sourceline
case slope_d: // d
case slope_flags: // flags
case slope_normal: // normal
case slope_refpos: // refpos
default:
return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]);
case slope_o: { // o
luaL_checktype(L, 3, LUA_TTABLE);
lua_getfield(L, 3, "x");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 3, 1);
}
if (!lua_isnil(L, -1))
slope->o.x = luaL_checkfixed(L, -1);
else
slope->o.x = 0;
lua_pop(L, 1);
lua_getfield(L, 3, "y");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 3, 2);
}
if (!lua_isnil(L, -1))
slope->o.y = luaL_checkfixed(L, -1);
else
slope->o.y = 0;
lua_pop(L, 1);
lua_getfield(L, 3, "z");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 3, 3);
}
if (!lua_isnil(L, -1))
slope->o.z = luaL_checkfixed(L, -1);
else
slope->o.z = 0;
lua_pop(L, 1);
break;
}
case slope_zdelta: { // zdelta, this is temp until i figure out wtf to do
slope->zdelta = luaL_checkfixed(L, 3);
slope->zangle = R_PointToAngle2(0, 0, FRACUNIT, -slope->zdelta);
P_CalculateSlopeNormal(slope);
break;
}
case slope_zangle: { // zangle
angle_t zangle = luaL_checkangle(L, 3);
if (zangle == ANGLE_90 || zangle == ANGLE_270)
return luaL_error(L, "invalid zangle for slope!");
slope->zangle = zangle;
slope->zdelta = -FINETANGENT(((slope->zangle+ANGLE_90)>>ANGLETOFINESHIFT) & 4095);
P_CalculateSlopeNormal(slope);
break;
}
case slope_xydirection: // xydirection
slope->xydirection = luaL_checkangle(L, 3);
slope->d.x = -FINECOSINE((slope->xydirection>>ANGLETOFINESHIFT) & FINEMASK);
slope->d.y = -FINESINE((slope->xydirection>>ANGLETOFINESHIFT) & FINEMASK);
P_CalculateSlopeNormal(slope);
break;
}
return 0;
}
static int vector2_get(lua_State *L)
{
vector2_t *vec = *((vector2_t **)luaL_checkudata(L, 1, META_VECTOR2));
enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
if (!vec)
return luaL_error(L, "accessed vector2_t doesn't exist anymore.");
switch(field)
{
case vector_x: lua_pushfixed(L, vec->x); return 1;
case vector_y: lua_pushfixed(L, vec->y); return 1;
default: break;
}
return 0;
}
static int vector3_get(lua_State *L)
{
vector3_t *vec = *((vector3_t **)luaL_checkudata(L, 1, META_VECTOR3));
enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
if (!vec)
return luaL_error(L, "accessed vector3_t doesn't exist anymore.");
switch(field)
{
case vector_x: lua_pushfixed(L, vec->x); return 1;
case vector_y: lua_pushfixed(L, vec->y); return 1;
case vector_z: lua_pushfixed(L, vec->z); return 1;
default: break;
}
return 0;
}
#endif
static int lib_getMapheaderinfo(lua_State *L)
{
// i -> mapheaderinfo[i-1]
@ -1317,6 +1592,26 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
#ifdef ESLOPE
luaL_newmetatable(L, META_SLOPE);
lua_pushcfunction(L, slope_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, slope_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
luaL_newmetatable(L, META_VECTOR2);
lua_pushcfunction(L, vector2_get);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_newmetatable(L, META_VECTOR3);
lua_pushcfunction(L, vector3_get);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
#endif
luaL_newmetatable(L, META_MAPHEADER);
lua_pushcfunction(L, mapheaderinfo_get);
lua_setfield(L, -2, "__index");

View File

@ -80,7 +80,12 @@ enum mobj_e {
mobj_extravalue1,
mobj_extravalue2,
mobj_cusval,
#ifdef ESLOPE
mobj_cvmem,
mobj_standingslope
#else
mobj_cvmem
#endif
};
static const char *const mobj_opt[] = {
@ -140,6 +145,9 @@ static const char *const mobj_opt[] = {
"extravalue2",
"cusval",
"cvmem",
#ifdef ESLOPE
"standingslope",
#endif
NULL};
#define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
@ -343,6 +351,11 @@ static int mobj_get(lua_State *L)
case mobj_cvmem:
lua_pushinteger(L, mo->cvmem);
break;
#ifdef ESLOPE
case mobj_standingslope:
LUA_PushUserdata(L, mo->standingslope, META_SLOPE);
break;
#endif
default: // extra custom variables in Lua memory
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));
@ -634,6 +647,10 @@ static int mobj_set(lua_State *L)
case mobj_cvmem:
mo->cvmem = luaL_checkinteger(L, 3);
break;
#ifdef ESLOPE
case mobj_standingslope:
return NOSET;
#endif
default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));

View File

@ -22,6 +22,9 @@
#include "byteptr.h"
#include "p_saveg.h"
#include "p_local.h"
#ifdef ESLOPE
#include "p_slopes.h" // for P_SlopeById
#endif
#ifdef LUA_ALLOW_BYTECODE
#include "d_netfil.h" // for LUA_DumpFile
#endif
@ -48,6 +51,7 @@ static lua_CFunction liblist[] = {
LUA_SkinLib, // skin_t, skins[]
LUA_ThinkerLib, // thinker_t
LUA_MapLib, // line_t, side_t, sector_t, subsector_t
LUA_BlockmapLib, // blockmap stuff
LUA_HudLib, // HUD stuff
NULL
};
@ -170,6 +174,7 @@ static inline void LUA_LoadFile(MYFILE *f, char *name)
LUA_ClearState();
lua_pushinteger(gL, f->wad);
lua_setfield(gL, LUA_REGISTRYINDEX, "WAD");
if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, 0, 0)) {
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
lua_pop(gL,1);
@ -189,17 +194,23 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump)
W_ReadLumpPwad(wad, lump, f.data);
f.curpos = f.data;
len = strlen(wadfiles[wad]->filename);
name = malloc(len+10);
strcpy(name, wadfiles[wad]->filename);
if (!fasticmp(&name[len - 4], ".lua")) {
// If it's not a .lua file, copy the lump name in too.
name[len] = '|';
M_Memcpy(name+len+1, wadfiles[wad]->lumpinfo[lump].name, 8);
name[len+9] = '\0';
len = strlen(wadfiles[wad]->filename); // length of file name
if (wadfiles[wad]->type == RET_LUA)
{
name = malloc(len+1);
strcpy(name, wadfiles[wad]->filename);
}
else // If it's not a .lua file, copy the lump name in too.
{
lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump];
len += 1 + strlen(lump_p->name2); // length of file name, '|', and lump name
name = malloc(len+1);
sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->name2);
name[len] = '\0';
}
LUA_LoadFile(&f, name);
LUA_LoadFile(&f, name); // actually load file!
free(name);
Z_Free(f.data);
@ -457,6 +468,9 @@ enum
ARCH_SIDE,
ARCH_SUBSECTOR,
ARCH_SECTOR,
#ifdef ESLOPE
ARCH_SLOPE,
#endif
ARCH_MAPHEADER,
ARCH_TEND=0xFF,
@ -476,6 +490,9 @@ static const struct {
{META_SIDE, ARCH_SIDE},
{META_SUBSECTOR,ARCH_SUBSECTOR},
{META_SECTOR, ARCH_SECTOR},
#ifdef ESLOPE
{META_SLOPE, ARCH_SLOPE},
#endif
{META_MAPHEADER, ARCH_MAPHEADER},
{NULL, ARCH_NULL}
};
@ -528,9 +545,23 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
break;
}
case LUA_TSTRING:
{
UINT16 len = (UINT16)lua_objlen(gL, myindex); // get length of string, including embedded zeros
const char *s = lua_tostring(gL, myindex);
UINT16 i = 0;
WRITEUINT8(save_p, ARCH_STRING);
WRITESTRING(save_p, lua_tostring(gL, myindex));
// 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
WRITEUINT16(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;
@ -666,6 +697,19 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
}
break;
}
#ifdef ESLOPE
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;
}
#endif
case ARCH_MAPHEADER:
{
mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
@ -769,11 +813,19 @@ static void ArchiveTables(void)
lua_pushnil(gL);
while (lua_next(gL, -2))
{
ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
// Write key
e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise)
{
lua_pushvalue(gL, -2);
CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -1), luaL_typename(gL, -1), i);
lua_pop(gL, 1);
}
// 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)
else if (e == 2) // invalid value type
{
lua_pushvalue(gL, -2);
CONS_Alert(CONS_ERROR, "Type of value for table %d entry '%s' (%s) could not be archived!\n", i, lua_tostring(gL, -1), luaL_typename(gL, -1));
@ -803,9 +855,19 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
break;
case ARCH_STRING:
{
char value[1024];
READSTRING(save_p, value);
lua_pushstring(gL, value);
UINT16 len = READUINT16(save_p); // length of string, including embedded zeros
char *value;
UINT16 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
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:
@ -852,6 +914,11 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
case ARCH_SECTOR:
LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_SECTOR);
break;
#ifdef ESLOPE
case ARCH_SLOPE:
LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE);
break;
#endif
case ARCH_MAPHEADER:
LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER);
break;
@ -915,11 +982,17 @@ static void UnArchiveTables(void)
lua_rawgeti(gL, TABLESINDEX, i);
while (true)
{
if (UnArchiveValue(TABLESINDEX) == 1)
if (UnArchiveValue(TABLESINDEX) == 1) // read key
break;
if (UnArchiveValue(TABLESINDEX) == 2)
if (UnArchiveValue(TABLESINDEX) == 2) // read value
n++;
lua_rawset(gL, -3);
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);
}
lua_pop(gL, 1);
}

View File

@ -214,4 +214,4 @@ void M_FindResponseFile(void)
break;
}
}
}

View File

@ -57,6 +57,8 @@
#include "st_stuff.h"
#include "i_sound.h"
#include "i_joy.h" // for joystick menu controls
// Condition Sets
#include "m_cond.h"
@ -278,7 +280,7 @@ static void M_SetupMultiPlayer2(INT32 choice);
// Split into multiple parts due to size
// Controls
menu_t OP_ControlsDef, OP_ControlListDef, OP_MoveControlsDef;
menu_t OP_MPControlsDef, OP_CameraControlsDef, OP_MiscControlsDef;
menu_t OP_MPControlsDef, OP_MiscControlsDef;
menu_t OP_P1ControlsDef, OP_P2ControlsDef, OP_MouseOptionsDef;
menu_t OP_Mouse2OptionsDef, OP_Joystick1Def, OP_Joystick2Def;
static void M_VideoModeMenu(INT32 choice);
@ -1047,20 +1049,30 @@ static menuitem_t OP_ControlListMenu[] =
{
{IT_SUBMENU | IT_STRING, NULL, "Movement Controls...", &OP_MoveControlsDef, 10},
{IT_SUBMENU | IT_STRING, NULL, "Multiplayer Controls...", &OP_MPControlsDef, 20},
{IT_SUBMENU | IT_STRING, NULL, "Camera Controls...", &OP_CameraControlsDef, 30},
{IT_SUBMENU | IT_STRING, NULL, "Miscellaneous Controls...", &OP_MiscControlsDef, 40},
{IT_SUBMENU | IT_STRING, NULL, "Miscellaneous Controls...", &OP_MiscControlsDef, 30},
};
static menuitem_t OP_MoveControlsMenu[] =
{
{IT_CALL | IT_STRING2, NULL, "Forward", M_ChangeControl, gc_forward },
{IT_CALL | IT_STRING2, NULL, "Reverse", M_ChangeControl, gc_backward },
{IT_CALL | IT_STRING2, NULL, "Turn Left", M_ChangeControl, gc_turnleft },
{IT_CALL | IT_STRING2, NULL, "Turn Right", M_ChangeControl, gc_turnright },
{IT_CALL | IT_STRING2, NULL, "Jump", M_ChangeControl, gc_jump },
{IT_CALL | IT_STRING2, NULL, "Spin", M_ChangeControl, gc_use },
{IT_CALL | IT_STRING2, NULL, "Strafe Left", M_ChangeControl, gc_strafeleft },
{IT_CALL | IT_STRING2, NULL, "Strafe Right", M_ChangeControl, gc_straferight},
{IT_HEADER, NULL, " Movement", NULL, 0},
{IT_CALL | IT_STRING2, NULL, "Move Forward", M_ChangeControl, gc_forward },
{IT_CALL | IT_STRING2, NULL, "Move Backward", M_ChangeControl, gc_backward },
{IT_CALL | IT_STRING2, NULL, "Move Left", M_ChangeControl, gc_strafeleft },
{IT_CALL | IT_STRING2, NULL, "Move Right", M_ChangeControl, gc_straferight },
{IT_CALL | IT_STRING2, NULL, "Jump", M_ChangeControl, gc_jump },
{IT_CALL | IT_STRING2, NULL, "Spin", M_ChangeControl, gc_use },
{IT_HEADER, NULL, " Camera", NULL, 0},
{IT_CALL | IT_STRING2, NULL, "Look Up", M_ChangeControl, gc_lookup },
{IT_CALL | IT_STRING2, NULL, "Look Down", M_ChangeControl, gc_lookdown },
{IT_CALL | IT_STRING2, NULL, "Turn Left", M_ChangeControl, gc_turnleft },
{IT_CALL | IT_STRING2, NULL, "Turn Right", M_ChangeControl, gc_turnright },
{IT_CALL | IT_STRING2, NULL, "Center View", M_ChangeControl, gc_centerview },
{IT_CALL | IT_STRING2, NULL, "Toggle Mouselook", M_ChangeControl, gc_mouseaiming },
{IT_CALL | IT_STRING2, NULL, "Toggle Third-Person", M_ChangeControl, gc_camtoggle},
{IT_CALL | IT_STRING2, NULL, "Reset Camera", M_ChangeControl, gc_camreset },
{IT_HEADER, NULL, " Advanced", NULL, 0},
{IT_CALL | IT_STRING2, NULL, "Rotate Camera L", M_ChangeControl, gc_camleft },
{IT_CALL | IT_STRING2, NULL, "Rotate Camera R", M_ChangeControl, gc_camright },
};
static menuitem_t OP_MPControlsMenu[] =
@ -1082,18 +1094,6 @@ static menuitem_t OP_MPControlsMenu[] =
{IT_CALL | IT_STRING2, NULL, "Ring Toss Normal", M_ChangeControl, gc_firenormal },
};
static menuitem_t OP_CameraControlsMenu[] =
{
{IT_CALL | IT_STRING2, NULL, "Look Up", M_ChangeControl, gc_lookup },
{IT_CALL | IT_STRING2, NULL, "Look Down", M_ChangeControl, gc_lookdown },
{IT_CALL | IT_STRING2, NULL, "Rotate Camera L", M_ChangeControl, gc_camleft },
{IT_CALL | IT_STRING2, NULL, "Rotate Camera R", M_ChangeControl, gc_camright },
{IT_CALL | IT_STRING2, NULL, "Center View", M_ChangeControl, gc_centerview },
{IT_CALL | IT_STRING2, NULL, "Mouselook", M_ChangeControl, gc_mouseaiming },
{IT_CALL | IT_STRING2, NULL, "Reset Camera", M_ChangeControl, gc_camreset },
{IT_CALL | IT_STRING2, NULL, "Toggle Chasecam", M_ChangeControl, gc_camtoggle },
};
static menuitem_t OP_MiscControlsMenu[] =
{
{IT_CALL | IT_STRING2, NULL, "Custom Action 1", M_ChangeControl, gc_custom1 },
@ -1101,6 +1101,10 @@ static menuitem_t OP_MiscControlsMenu[] =
{IT_CALL | IT_STRING2, NULL, "Custom Action 3", M_ChangeControl, gc_custom3 },
{IT_CALL | IT_STRING2, NULL, "Pause", M_ChangeControl, gc_pause },
{IT_CALL | IT_STRING2, NULL, "Screenshot", M_ChangeControl, gc_screenshot },
{IT_CALL | IT_STRING2, NULL, "Toggle GIF Recording", M_ChangeControl, gc_recordgif },
{IT_CALL | IT_STRING2, NULL, "Open/Close Menu (ESC)", M_ChangeControl, gc_systemmenu },
{IT_CALL | IT_STRING2, NULL, "Change Viewpoint", M_ChangeControl, gc_viewpoint },
{IT_CALL | IT_STRING2, NULL, "Console", M_ChangeControl, gc_console },
};
@ -1113,6 +1117,9 @@ static menuitem_t OP_Joystick1Menu[] =
{IT_STRING | IT_CVAR, NULL, "Axis For Looking" , &cv_lookaxis , 60},
{IT_STRING | IT_CVAR, NULL, "Axis For Firing" , &cv_fireaxis , 70},
{IT_STRING | IT_CVAR, NULL, "Axis For NFiring" , &cv_firenaxis , 80},
{IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 100},
{IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 110},
};
static menuitem_t OP_Joystick2Menu[] =
@ -1124,6 +1131,9 @@ static menuitem_t OP_Joystick2Menu[] =
{IT_STRING | IT_CVAR, NULL, "Axis For Looking" , &cv_lookaxis2 , 60},
{IT_STRING | IT_CVAR, NULL, "Axis For Firing" , &cv_fireaxis2 , 70},
{IT_STRING | IT_CVAR, NULL, "Axis For NFiring" , &cv_firenaxis2 , 80},
{IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2, 100},
{IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 110},
};
static menuitem_t OP_JoystickSetMenu[] =
@ -1142,13 +1152,14 @@ static menuitem_t OP_MouseOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Use Mouse", &cv_usemouse, 10},
{IT_STRING | IT_CVAR, NULL, "Always MouseLook", &cv_alwaysfreelook, 30},
{IT_STRING | IT_CVAR, NULL, "Mouse Move", &cv_mousemove, 40},
{IT_STRING | IT_CVAR, NULL, "Invert Mouse", &cv_invertmouse, 50},
{IT_STRING | IT_CVAR, NULL, "First-Person MouseLook", &cv_alwaysfreelook, 30},
{IT_STRING | IT_CVAR, NULL, "Third-Person MouseLook", &cv_chasefreelook, 40},
{IT_STRING | IT_CVAR, NULL, "Mouse Move", &cv_mousemove, 50},
{IT_STRING | IT_CVAR, NULL, "Invert Mouse", &cv_invertmouse, 60},
{IT_STRING | IT_CVAR | IT_CV_SLIDER,
NULL, "Mouse X Speed", &cv_mousesens, 60},
NULL, "Mouse X Speed", &cv_mousesens, 70},
{IT_STRING | IT_CVAR | IT_CV_SLIDER,
NULL, "Mouse Y Speed", &cv_mouseysens, 70},
NULL, "Mouse Y Speed", &cv_mouseysens, 80},
};
static menuitem_t OP_Mouse2OptionsMenu[] =
@ -1156,13 +1167,14 @@ static menuitem_t OP_Mouse2OptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Use Mouse 2", &cv_usemouse2, 10},
{IT_STRING | IT_CVAR, NULL, "Second Mouse Serial Port",
&cv_mouse2port, 20},
{IT_STRING | IT_CVAR, NULL, "Always MouseLook", &cv_alwaysfreelook2, 30},
{IT_STRING | IT_CVAR, NULL, "Mouse Move", &cv_mousemove2, 40},
{IT_STRING | IT_CVAR, NULL, "Invert Mouse", &cv_invertmouse2, 50},
{IT_STRING | IT_CVAR, NULL, "First-Person MouseLook", &cv_alwaysfreelook2, 30},
{IT_STRING | IT_CVAR, NULL, "Third-Person MouseLook", &cv_chasefreelook2, 40},
{IT_STRING | IT_CVAR, NULL, "Mouse Move", &cv_mousemove2, 50},
{IT_STRING | IT_CVAR, NULL, "Invert Mouse", &cv_invertmouse2, 60},
{IT_STRING | IT_CVAR | IT_CV_SLIDER,
NULL, "Mouse X Speed", &cv_mousesens2, 60},
NULL, "Mouse X Speed", &cv_mousesens2, 70},
{IT_STRING | IT_CVAR | IT_CV_SLIDER,
NULL, "Mouse Y Speed", &cv_mouseysens2, 70},
NULL, "Mouse Y Speed", &cv_mouseysens2, 80},
};
static menuitem_t OP_VideoOptionsMenu[] =
@ -1711,7 +1723,6 @@ menu_t OP_ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_ControlsMenu, &OP_MainDe
menu_t OP_ControlListDef = DEFAULTMENUSTYLE("M_CONTRO", OP_ControlListMenu, &OP_ControlsDef, 60, 30);
menu_t OP_MoveControlsDef = CONTROLMENUSTYLE(OP_MoveControlsMenu, &OP_ControlListDef);
menu_t OP_MPControlsDef = CONTROLMENUSTYLE(OP_MPControlsMenu, &OP_ControlListDef);
menu_t OP_CameraControlsDef = CONTROLMENUSTYLE(OP_CameraControlsMenu, &OP_ControlListDef);
menu_t OP_MiscControlsDef = CONTROLMENUSTYLE(OP_MiscControlsMenu, &OP_ControlListDef);
menu_t OP_P1ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_P1ControlsMenu, &OP_ControlsDef, 60, 30);
menu_t OP_P2ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_P2ControlsMenu, &OP_ControlsDef, 60, 30);
@ -2127,6 +2138,7 @@ boolean M_Responder(event_t *ev)
INT32 ch = -1;
// INT32 i;
static tic_t joywait = 0, mousewait = 0;
static INT32 pjoyx = 0, pjoyy = 0;
static INT32 pmousex = 0, pmousey = 0;
static INT32 lastx = 0, lasty = 0;
void (*routine)(INT32 choice); // for some casting problem
@ -2142,63 +2154,84 @@ boolean M_Responder(event_t *ev)
// (but still allow shift keyup so caps doesn't get stuck)
return false;
}
else if (ev->type == ev_keydown)
{
ch = ev->data1;
// added 5-2-98 remap virtual keys (mouse & joystick buttons)
switch (ch)
{
case KEY_MOUSE1:
case KEY_JOY1:
case KEY_JOY1 + 2:
ch = KEY_ENTER;
break;
case KEY_JOY1 + 3:
ch = 'n';
break;
case KEY_MOUSE1 + 1:
case KEY_JOY1 + 1:
ch = KEY_BACKSPACE;
break;
case KEY_HAT1:
ch = KEY_UPARROW;
break;
case KEY_HAT1 + 1:
ch = KEY_DOWNARROW;
break;
case KEY_HAT1 + 2:
ch = KEY_LEFTARROW;
break;
case KEY_HAT1 + 3:
ch = KEY_RIGHTARROW;
break;
}
}
else if (menuactive)
{
if (ev->type == ev_joystick && ev->data1 == 0 && joywait < I_GetTime())
if (ev->type == ev_keydown)
{
if (ev->data3 == -1)
ch = ev->data1;
// added 5-2-98 remap virtual keys (mouse & joystick buttons)
switch (ch)
{
ch = KEY_UPARROW;
joywait = I_GetTime() + NEWTICRATE/7;
case KEY_MOUSE1:
case KEY_JOY1:
ch = KEY_ENTER;
break;
case KEY_JOY1 + 3:
ch = 'n';
break;
case KEY_MOUSE1 + 1:
case KEY_JOY1 + 1:
ch = KEY_ESCAPE;
break;
case KEY_JOY1 + 2:
ch = KEY_BACKSPACE;
break;
case KEY_HAT1:
ch = KEY_UPARROW;
break;
case KEY_HAT1 + 1:
ch = KEY_DOWNARROW;
break;
case KEY_HAT1 + 2:
ch = KEY_LEFTARROW;
break;
case KEY_HAT1 + 3:
ch = KEY_RIGHTARROW;
break;
}
else if (ev->data3 == 1)
}
else if (ev->type == ev_joystick && ev->data1 == 0 && joywait < I_GetTime())
{
const INT32 jdeadzone = JOYAXISRANGE/4;
if (ev->data3 != INT32_MAX)
{
ch = KEY_DOWNARROW;
joywait = I_GetTime() + NEWTICRATE/7;
if (Joystick.bGamepadStyle || abs(ev->data3) > jdeadzone)
{
if (ev->data3 < 0 && pjoyy >= 0)
{
ch = KEY_UPARROW;
joywait = I_GetTime() + NEWTICRATE/7;
}
else if (ev->data3 > 0 && pjoyy <= 0)
{
ch = KEY_DOWNARROW;
joywait = I_GetTime() + NEWTICRATE/7;
}
pjoyy = ev->data3;
}
else
pjoyy = 0;
}
if (ev->data2 == -1)
if (ev->data2 != INT32_MAX)
{
ch = KEY_LEFTARROW;
joywait = I_GetTime() + NEWTICRATE/17;
}
else if (ev->data2 == 1)
{
ch = KEY_RIGHTARROW;
joywait = I_GetTime() + NEWTICRATE/17;
if (Joystick.bGamepadStyle || abs(ev->data2) > jdeadzone)
{
if (ev->data2 < 0 && pjoyx >= 0)
{
ch = KEY_LEFTARROW;
joywait = I_GetTime() + NEWTICRATE/17;
}
else if (ev->data2 > 0 && pjoyx <= 0)
{
ch = KEY_RIGHTARROW;
joywait = I_GetTime() + NEWTICRATE/17;
}
pjoyx = ev->data2;
}
else
pjoyx = 0;
}
}
else if (ev->type == ev_mouse && mousewait < I_GetTime())
@ -2232,9 +2265,13 @@ boolean M_Responder(event_t *ev)
}
}
}
else if (ev->type == ev_keydown) // Preserve event for other responders
ch = ev->data1;
if (ch == -1)
return false;
else if (ch == gamecontrol[gc_systemmenu][0] || ch == gamecontrol[gc_systemmenu][1]) // allow remappable ESC key
ch = KEY_ESCAPE;
// F-Keys
if (!menuactive)
@ -2636,7 +2673,7 @@ void M_StartControlPanel(void)
MPauseMenu[mpause_switchteam].status = IT_DISABLED;
MPauseMenu[mpause_psetup].status = IT_DISABLED;
if ((server || adminplayer == consoleplayer))
if ((server || IsPlayerAdmin(consoleplayer)))
{
MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL;
MPauseMenu[mpause_addons].status = IT_STRING | IT_CALL;
@ -4519,7 +4556,7 @@ static void M_Options(INT32 choice)
(void)choice;
// if the player is not admin or server, disable server options
OP_MainMenu[5].status = (Playing() && !(server || adminplayer == consoleplayer)) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);
OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);
// if the player is playing _at all_, disable the erase data options
OP_DataOptionsMenu[1].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);
@ -7458,6 +7495,7 @@ static void M_DrawControl(void)
}
static INT32 controltochange;
static char controltochangetext[55];
static void M_ChangecontrolResponse(event_t *ev)
{
@ -7465,8 +7503,8 @@ static void M_ChangecontrolResponse(event_t *ev)
INT32 found;
INT32 ch = ev->data1;
// ESCAPE cancels
if (ch != KEY_ESCAPE)
// ESCAPE cancels; dummy out PAUSE
if (ch != KEY_ESCAPE && ch != KEY_PAUSE)
{
switch (ev->type)
@ -7525,8 +7563,28 @@ static void M_ChangecontrolResponse(event_t *ev)
G_CheckDoubleUsage(ch);
setupcontrols[control][found] = ch;
}
S_StartSound(NULL, sfx_strpst);
}
else if (ch == KEY_PAUSE)
{
static char tmp[155];
menu_t *prev = currentMenu->prevMenu;
if (controltochange == gc_pause)
sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nyou may select another key. \n\nHit another key for\n%s\nESC for Cancel"),
controltochangetext);
else
sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nit is not configurable. \n\nHit another key for\n%s\nESC for Cancel"),
controltochangetext);
M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER);
currentMenu->prevMenu = prev;
S_StartSound(NULL, sfx_s3k42);
return;
}
else
S_StartSound(NULL, sfx_skid);
M_StopMessage(0);
}
@ -7538,6 +7596,7 @@ static void M_ChangeControl(INT32 choice)
controltochange = currentMenu->menuitems[choice].alphaKey;
sprintf(tmp, M_GetText("Hit the new key for\n%s\nESC for Cancel"),
currentMenu->menuitems[choice].text);
strncpy(controltochangetext, currentMenu->menuitems[choice].text, 55);
M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER);
}

View File

@ -37,6 +37,7 @@
#include "d_main.h"
#include "m_argv.h"
#include "i_system.h"
#include "command.h" // cv_execversion
#include "m_anigif.h"
@ -440,7 +441,18 @@ void Command_LoadConfig_f(void)
strcpy(configfile, COM_Argv(1));
FIL_ForceExtension(configfile, ".cfg");
// temporarily reset execversion to default
cv_execversion.flags &= ~CV_HIDEN;
COM_BufInsertText(va("%s \"%s\"\n", cv_execversion.name, cv_execversion.defaultvalue));
CV_InitFilterVar();
// exec the config
COM_BufInsertText(va("exec \"%s\"\n", configfile));
// don't filter anymore vars and don't let this convsvar be changed
COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, MODVERSION));
cv_execversion.flags |= CV_HIDEN;
}
/** Saves the current configuration and loads another.
@ -477,10 +489,23 @@ void M_FirstLoadConfig(void)
// load default control
G_Controldefault();
// register execversion here before we load any configs
CV_RegisterVar(&cv_execversion);
// temporarily reset execversion to default
// we shouldn't need to do this, but JUST in case...
cv_execversion.flags &= ~CV_HIDEN;
COM_BufInsertText(va("%s \"%s\"\n", cv_execversion.name, cv_execversion.defaultvalue));
CV_InitFilterVar();
// load config, make sure those commands doesnt require the screen...
COM_BufInsertText(va("exec \"%s\"\n", configfile));
// no COM_BufExecute() needed; that does it right away
// don't filter anymore vars and don't let this convsvar be changed
COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, MODVERSION));
cv_execversion.flags |= CV_HIDEN;
// make sure I_Quit() will write back the correct config
// (do not write back the config if it crash before)
gameconfig_loaded = true;
@ -493,6 +518,7 @@ void M_FirstLoadConfig(void)
void M_SaveConfig(const char *filename)
{
FILE *f;
char *filepath;
// make sure not to write back the config until it's been correctly loaded
if (!gameconfig_loaded)
@ -507,13 +533,20 @@ void M_SaveConfig(const char *filename)
return;
}
f = fopen(filename, "w");
// append srb2home to beginning of filename
// but check if srb2home isn't already there, first
if (!strstr(filename, srb2home))
filepath = va(pandf,srb2home, filename);
else
filepath = Z_StrDup(filename);
f = fopen(filepath, "w");
// change it only if valid
if (f)
strcpy(configfile, filename);
strcpy(configfile, filepath);
else
{
CONS_Alert(CONS_ERROR, M_GetText("Couldn't save game config file %s\n"), filename);
CONS_Alert(CONS_ERROR, M_GetText("Couldn't save game config file %s\n"), filepath);
return;
}
}
@ -536,6 +569,10 @@ void M_SaveConfig(const char *filename)
// header message
fprintf(f, "// SRB2 configuration file.\n");
// print execversion FIRST, because subsequent consvars need to be filtered
// always print current MODVERSION
fprintf(f, "%s \"%d\"\n", cv_execversion.name, MODVERSION);
// FIXME: save key aliases if ever implemented..
CV_SaveVariables(f);
@ -1494,9 +1531,9 @@ boolean M_ScreenshotResponder(event_t *ev)
return false;
ch = ev->data1;
if (ch == KEY_F8)
if (ch == KEY_F8 || ch == gamecontrol[gc_screenshot][0] || ch == gamecontrol[gc_screenshot][1]) // remappable F8
M_ScreenShot();
else if (ch == KEY_F9)
else if (ch == KEY_F9 || ch == gamecontrol[gc_recordgif][0] || ch == gamecontrol[gc_recordgif][1]) // remappable F9
((moviemode) ? M_StopMovie : M_StartMovie)();
else
return false;

View File

@ -811,6 +811,8 @@ void T_BounceCheese(levelspecthink_t *bouncer)
{
bouncer->sector->ceilingheight = actionsector->ceilingheight;
bouncer->sector->floorheight = bouncer->sector->ceilingheight - (halfheight*2);
T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling
T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor
P_RecalcPrecipInSector(actionsector);
bouncer->sector->ceilingdata = NULL;
bouncer->sector->floordata = NULL;
@ -825,6 +827,8 @@ void T_BounceCheese(levelspecthink_t *bouncer)
{
bouncer->sector->ceilingheight = floorheight + (halfheight << 1);
bouncer->sector->floorheight = floorheight;
T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling
T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor
P_RecalcPrecipInSector(actionsector);
bouncer->sector->ceilingdata = NULL;
bouncer->sector->floordata = NULL;
@ -841,9 +845,9 @@ void T_BounceCheese(levelspecthink_t *bouncer)
}
T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->ceilingheight -
70*FRACUNIT, 0, 1, -1); // move floor
70*FRACUNIT, 0, 1, -1); // move ceiling
T_MovePlane(bouncer->sector, bouncer->speed/2, bouncer->sector->floorheight - 70*FRACUNIT,
0, 0, -1); // move ceiling
0, 0, -1); // move floor
bouncer->sector->floorspeed = -bouncer->speed/2;
bouncer->sector->ceilspeed = 42;
@ -893,6 +897,8 @@ void T_BounceCheese(levelspecthink_t *bouncer)
{
bouncer->sector->floorheight = bouncer->floorwasheight;
bouncer->sector->ceilingheight = bouncer->ceilingwasheight;
T_MovePlane(bouncer->sector, 0, bouncer->sector->ceilingheight, 0, 1, -1); // update things on ceiling
T_MovePlane(bouncer->sector, 0, bouncer->sector->floorheight, 0, 0, -1); // update things on floor
bouncer->sector->ceilingdata = NULL;
bouncer->sector->floordata = NULL;
bouncer->sector->floorspeed = 0;
@ -1818,6 +1824,7 @@ void T_ThwompSector(levelspecthink_t *thwomp)
#define ceilingwasheight vars[5]
fixed_t thwompx, thwompy;
sector_t *actionsector;
ffloor_t *rover = NULL;
INT32 secnum;
// If you just crashed down, wait a second before coming back up.
@ -1832,7 +1839,16 @@ void T_ThwompSector(levelspecthink_t *thwomp)
secnum = P_FindSectorFromTag((INT16)thwomp->vars[0], -1);
if (secnum > 0)
{
actionsector = &sectors[secnum];
// Look for thwomp FFloor
for (rover = actionsector->ffloors; rover; rover = rover->next)
{
if (rover->master == thwomp->sourceline)
break;
}
}
else
return; // Bad bad bad!
@ -1921,10 +1937,13 @@ void T_ThwompSector(levelspecthink_t *thwomp)
{
mobj_t *mp = (void *)&actionsector->soundorg;
if (thwomp->sourceline->flags & ML_EFFECT4)
S_StartSound(mp, sides[thwomp->sourceline->sidenum[0]].textureoffset>>FRACBITS);
else
S_StartSound(mp, sfx_thwomp);
if (!rover || (rover->flags & FF_EXISTS))
{
if (thwomp->sourceline->flags & ML_EFFECT4)
S_StartSound(mp, sides[thwomp->sourceline->sidenum[0]].textureoffset>>FRACBITS);
else
S_StartSound(mp, sfx_thwomp);
}
thwomp->direction = 1; // start heading back up
thwomp->distance = TICRATE; // but only after a small delay
@ -1938,18 +1957,22 @@ void T_ThwompSector(levelspecthink_t *thwomp)
thinker_t *th;
mobj_t *mo;
// scan the thinkers to find players!
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (!rover || (rover->flags & FF_EXISTS))
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mo = (mobj_t *)th;
if (mo->type == MT_PLAYER && mo->health && mo->z <= thwomp->sector->ceilingheight
&& P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT)
// scan the thinkers to find players!
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
thwomp->direction = -1;
break;
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mo = (mobj_t *)th;
if (mo->type == MT_PLAYER && mo->health && mo->player && !mo->player->spectator
&& mo->z <= thwomp->sector->ceilingheight
&& P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT)
{
thwomp->direction = -1;
break;
}
}
}
@ -2103,6 +2126,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
boolean floortouch = false;
fixed_t bottomheight, topheight;
msecnode_t *node;
ffloor_t *rover;
for (i = 0; i < MAXPLAYERS; i++)
{
@ -2150,6 +2174,19 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
{
targetsec = &sectors[targetsecnum];
// Find the FOF corresponding to the control linedef
for (rover = targetsec->ffloors; rover; rover = rover->next)
{
if (rover->master == sec->lines[i])
break;
}
if (!rover) // This should be impossible, but don't complain if it is the case somehow
continue;
if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there
continue;
for (j = 0; j < MAXPLAYERS; j++)
{
if (!playeringame[j])

View File

@ -777,14 +777,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
// not (your direction) xor (stored direction)
// In other words, you can't u-turn and respawn rings near the drone.
if (pl->bonustime && (pl->pflags & PF_NIGHTSMODE) && (INT32)leveltime > droneobj->extravalue2 && (
!(pl->anotherflyangle >= 90 && pl->anotherflyangle <= 270)
^ (droneobj->extravalue1 >= 90 && droneobj->extravalue1 <= 270)
!(pl->flyangle > 90 && pl->flyangle < 270)
^ (droneobj->extravalue1 > 90 && droneobj->extravalue1 < 270)
))
{
// Reload all the fancy ring stuff!
P_ReloadRings();
}
droneobj->extravalue1 = pl->anotherflyangle;
droneobj->extravalue1 = pl->flyangle;
droneobj->extravalue2 = (INT32)leveltime + TICRATE;
}

View File

@ -3506,7 +3506,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled
if (player->pflags & PF_FLIPCAM && !(player->pflags & PF_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP)
postimg = postimg_flip;
else if (player->awayviewtics && player->awayviewmobj != NULL) // Camera must obviously exist
else if (player->awayviewtics && player->awayviewmobj && !P_MobjWasRemoved(player->awayviewmobj)) // Camera must obviously exist
{
camera_t dummycam;
dummycam.subsector = player->awayviewmobj->subsector;
@ -9198,9 +9198,6 @@ ML_NOCLIMB : Direction not controllable
// the bumper in 30 degree increments.
mobj->threshold = (mthing->options & 15) % 12; // It loops over, etc
P_SetMobjState(mobj, mobj->info->spawnstate+mobj->threshold);
// you can shut up now, OBJECTFLIP. And all of the other options, for that matter.
mthing->options &= ~0xF;
break;
case MT_EGGCAPSULE:
if (mthing->angle <= 0)
@ -9388,6 +9385,14 @@ ML_NOCLIMB : Direction not controllable
}
}
// ignore MTF_ flags and return early
if (i == MT_NIGHTSBUMPER)
{
mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
mthing->mobj = mobj;
return;
}
mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
if ((mthing->options & MTF_AMBUSH)

View File

@ -489,16 +489,34 @@ static void P_NetArchiveWorld(void)
UINT8 *put;
// reload the map just to see difference
const mapsector_t *ms;
const mapsidedef_t *msd;
const maplinedef_t *mld;
mapsector_t *ms;
mapsidedef_t *msd;
maplinedef_t *mld;
const sector_t *ss = sectors;
UINT8 diff, diff2;
WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD);
put = save_p;
ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE);
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can get the data from the relevant lumps
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
#define retrieve_mapdata(d, f)\
d = Z_Malloc((f)->size, PU_CACHE, NULL); \
M_Memcpy(d, wadData + (f)->filepos, (f)->size)
retrieve_mapdata(ms, fileinfo + ML_SECTORS);
retrieve_mapdata(mld, fileinfo + ML_LINEDEFS);
retrieve_mapdata(msd, fileinfo + ML_SIDEDEFS);
#undef retrieve_mapdata
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
{
ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE);
mld = W_CacheLumpNum(lastloadedmaplumpnum+ML_LINEDEFS, PU_CACHE);
msd = W_CacheLumpNum(lastloadedmaplumpnum+ML_SIDEDEFS, PU_CACHE);
}
for (i = 0; i < numsectors; i++, ss++, ms++)
{
@ -950,6 +968,7 @@ typedef enum
tc_bouncecheese,
tc_startcrumble,
tc_marioblock,
tc_marioblockchecker,
tc_spikesector,
tc_floatsector,
tc_bridgethinker,
@ -1259,7 +1278,10 @@ static void SaveSpecialLevelThinker(const thinker_t *th, const UINT8 type)
size_t i;
WRITEUINT8(save_p, type);
for (i = 0; i < 16; i++)
{
WRITEFIXED(save_p, ht->vars[i]); //var[16]
WRITEFIXED(save_p, ht->var2s[i]); //var[16]
}
WRITEUINT32(save_p, SaveLine(ht->sourceline));
WRITEUINT32(save_p, SaveSector(ht->sector));
}
@ -1772,6 +1794,11 @@ static void P_NetArchiveThinkers(void)
SaveSpecialLevelThinker(th, tc_marioblock);
continue;
}
else if (th->function.acp1 == (actionf_p1)T_MarioBlockChecker)
{
SaveSpecialLevelThinker(th, tc_marioblockchecker);
continue;
}
else if (th->function.acp1 == (actionf_p1)T_SpikeSector)
{
SaveSpecialLevelThinker(th, tc_spikesector);
@ -2155,7 +2182,10 @@ static void LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
size_t i;
ht->thinker.function.acp1 = thinker;
for (i = 0; i < 16; i++)
{
ht->vars[i] = READFIXED(save_p); //var[16]
ht->var2s[i] = READFIXED(save_p); //var[16]
}
ht->sourceline = LoadLine(READUINT32(save_p));
ht->sector = LoadSector(READUINT32(save_p));
@ -2728,6 +2758,10 @@ static void P_NetUnArchiveThinkers(void)
LoadSpecialLevelThinker((actionf_p1)T_MarioBlock, 3);
break;
case tc_marioblockchecker:
LoadSpecialLevelThinker((actionf_p1)T_MarioBlockChecker, 0);
break;
case tc_spikesector:
LoadSpecialLevelThinker((actionf_p1)T_SpikeSector, 0);
break;

View File

@ -350,16 +350,13 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade)
* \param lump VERTEXES lump number.
* \sa ML_VERTEXES
*/
static inline void P_LoadVertexes(lumpnum_t lumpnum)
static inline void P_LoadRawVertexes(UINT8 *data, size_t i)
{
UINT8 *data;
size_t i;
mapvertex_t *ml;
vertex_t *li;
// Determine number of lumps:
// total lump length / vertex record length.
numvertexes = W_LumpLength(lumpnum) / sizeof (mapvertex_t);
numvertexes = i / sizeof (mapvertex_t);
if (numvertexes <= 0)
I_Error("Level has no vertices"); // instead of crashing
@ -367,9 +364,6 @@ static inline void P_LoadVertexes(lumpnum_t lumpnum)
// Allocate zone memory for buffer.
vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL);
// Load data into cache.
data = W_CacheLumpNum(lumpnum, PU_STATIC);
ml = (mapvertex_t *)data;
li = vertexes;
@ -379,11 +373,16 @@ static inline void P_LoadVertexes(lumpnum_t lumpnum)
li->x = SHORT(ml->x)<<FRACBITS;
li->y = SHORT(ml->y)<<FRACBITS;
}
}
// Free buffer memory.
static inline void P_LoadVertexes(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawVertexes(data, W_LumpLength(lumpnum));
Z_Free(data);
}
//
// Computes the line length in fracunits, the OpenGL render needs this
//
@ -423,20 +422,17 @@ static inline float P_SegLengthf(seg_t *seg)
* \param lump Lump number of the SEGS resource.
* \sa ::ML_SEGS
*/
static void P_LoadSegs(lumpnum_t lumpnum)
static void P_LoadRawSegs(UINT8 *data, size_t i)
{
UINT8 *data;
size_t i;
INT32 linedef, side;
mapseg_t *ml;
seg_t *li;
line_t *ldef;
numsegs = W_LumpLength(lumpnum) / sizeof (mapseg_t);
numsegs = i / sizeof (mapseg_t);
if (numsegs <= 0)
I_Error("Level has no segs"); // instead of crashing
segs = Z_Calloc(numsegs * sizeof (*segs), PU_LEVEL, NULL);
data = W_CacheLumpNum(lumpnum, PU_STATIC);
ml = (mapseg_t *)data;
li = segs;
@ -472,27 +468,30 @@ static void P_LoadSegs(lumpnum_t lumpnum)
li->numlights = 0;
li->rlights = NULL;
}
}
static void P_LoadSegs(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawSegs(data, W_LumpLength(lumpnum));
Z_Free(data);
}
/** Loads the SSECTORS resource from a level.
*
* \param lump Lump number of the SSECTORS resource.
* \sa ::ML_SSECTORS
*/
static inline void P_LoadSubsectors(lumpnum_t lumpnum)
static inline void P_LoadRawSubsectors(void *data, size_t i)
{
void *data;
size_t i;
mapsubsector_t *ms;
subsector_t *ss;
numsubsectors = W_LumpLength(lumpnum) / sizeof (mapsubsector_t);
numsubsectors = i / sizeof (mapsubsector_t);
if (numsubsectors <= 0)
I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)");
ss = subsectors = Z_Calloc(numsubsectors * sizeof (*subsectors), PU_LEVEL, NULL);
data = W_CacheLumpNum(lumpnum,PU_STATIC);
ms = (mapsubsector_t *)data;
@ -506,7 +505,12 @@ static inline void P_LoadSubsectors(lumpnum_t lumpnum)
#endif
ss->validcount = 0;
}
}
static void P_LoadSubsectors(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawSubsectors(data, W_LumpLength(lumpnum));
Z_Free(data);
}
@ -640,29 +644,31 @@ INT32 P_CheckLevelFlat(const char *flatname)
return (INT32)i;
}
static void P_LoadSectors(lumpnum_t lumpnum)
// Sets up the ingame sectors structures.
// Lumpnum is the lumpnum of a SECTORS lump.
static void P_LoadRawSectors(UINT8 *data, size_t i)
{
UINT8 *data;
size_t i;
mapsector_t *ms;
sector_t *ss;
levelflat_t *foundflats;
numsectors = W_LumpLength(lumpnum) / sizeof (mapsector_t);
// We count how many sectors we got.
numsectors = i / sizeof (mapsector_t);
if (numsectors <= 0)
I_Error("Level has no sectors");
// Allocate as much memory as we need into the global sectors table.
sectors = Z_Calloc(numsectors*sizeof (*sectors), PU_LEVEL, NULL);
data = W_CacheLumpNum(lumpnum,PU_STATIC);
//Fab : FIXME: allocate for whatever number of flats
// 512 different flats per level should be plenty
// Allocate a big chunk of memory as big as our MAXLEVELFLATS limit.
//Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty
foundflats = calloc(MAXLEVELFLATS, sizeof (*foundflats));
if (foundflats == NULL)
I_Error("Ran out of memory while loading sectors\n");
numlevelflats = 0;
// For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss.
ms = (mapsector_t *)data;
ss = sectors;
for (i = 0; i < numsectors; i++, ss++, ms++)
@ -670,9 +676,6 @@ static void P_LoadSectors(lumpnum_t lumpnum)
ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
//
// flats
//
ss->floorpic = P_AddLevelFlat(ms->floorpic, foundflats);
ss->ceilingpic = P_AddLevelFlat(ms->ceilingpic, foundflats);
@ -737,8 +740,6 @@ static void P_LoadSectors(lumpnum_t lumpnum)
#endif // ----- end special tricks -----
}
Z_Free(data);
// set the sky flat num
skyflatnum = P_AddLevelFlat(SKYFLATNAME, foundflats);
@ -750,22 +751,26 @@ static void P_LoadSectors(lumpnum_t lumpnum)
P_SetupLevelFlatAnims();
}
static void P_LoadSectors(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawSectors(data, W_LumpLength(lumpnum));
Z_Free(data);
}
//
// P_LoadNodes
//
static void P_LoadNodes(lumpnum_t lumpnum)
static void P_LoadRawNodes(UINT8 *data, size_t i)
{
UINT8 *data;
size_t i;
UINT8 j, k;
mapnode_t *mn;
node_t *no;
numnodes = W_LumpLength(lumpnum) / sizeof (mapnode_t);
numnodes = i / sizeof (mapnode_t);
if (numnodes <= 0)
I_Error("Level has no nodes");
nodes = Z_Calloc(numnodes * sizeof (*nodes), PU_LEVEL, NULL);
data = W_CacheLumpNum(lumpnum, PU_STATIC);
mn = (mapnode_t *)data;
no = nodes;
@ -783,7 +788,12 @@ static void P_LoadNodes(lumpnum_t lumpnum)
no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
}
}
}
static void P_LoadNodes(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawNodes(data, W_LumpLength(lumpnum));
Z_Free(data);
}
@ -918,18 +928,16 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum)
//
// P_LoadThings
//
static void P_PrepareThings(lumpnum_t lumpnum)
{
size_t i;
mapthing_t *mt;
UINT8 *data, *datastart;
nummapthings = W_LumpLength(lumpnum) / (5 * sizeof (INT16));
static void P_PrepareRawThings(UINT8 *data, size_t i)
{
mapthing_t *mt;
nummapthings = i / (5 * sizeof (INT16));
mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL);
// Spawn axis points first so they are
// at the front of the list for fast searching.
data = datastart = W_CacheLumpNum(lumpnum, PU_LEVEL);
mt = mapthings;
for (i = 0; i < nummapthings; i++, mt++)
{
@ -954,8 +962,13 @@ static void P_PrepareThings(lumpnum_t lumpnum)
break;
}
}
Z_Free(datastart);
}
static void P_PrepareThings(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_PrepareRawThings(data, W_LumpLength(lumpnum));
Z_Free(data);
}
static void P_LoadThings(void)
@ -1142,22 +1155,16 @@ void P_WriteThings(lumpnum_t lumpnum)
CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap);
}
//
// P_LoadLineDefs
//
static void P_LoadLineDefs(lumpnum_t lumpnum)
static void P_LoadRawLineDefs(UINT8 *data, size_t i)
{
UINT8 *data;
size_t i;
maplinedef_t *mld;
line_t *ld;
vertex_t *v1, *v2;
numlines = W_LumpLength(lumpnum) / sizeof (maplinedef_t);
numlines = i / sizeof (maplinedef_t);
if (numlines <= 0)
I_Error("Level has no linedefs");
lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL);
data = W_CacheLumpNum(lumpnum, PU_STATIC);
mld = (maplinedef_t *)data;
ld = lines;
@ -1179,7 +1186,7 @@ static void P_LoadLineDefs(lumpnum_t lumpnum)
ld->slopetype = ST_VERTICAL;
else if (!ld->dy)
ld->slopetype = ST_HORIZONTAL;
else if (FixedDiv(ld->dy, ld->dx) > 0)
else if ((ld->dy > 0) == (ld->dx > 0))
ld->slopetype = ST_POSITIVE;
else
ld->slopetype = ST_NEGATIVE;
@ -1219,7 +1226,7 @@ static void P_LoadLineDefs(lumpnum_t lumpnum)
if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides)
{
ld->sidenum[j] = 0xffff;
CONS_Debug(DBG_SETUP, "P_LoadLineDefs: linedef %s has out-of-range sidedef number\n", sizeu1(numlines-i-1));
CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has out-of-range sidedef number\n", sizeu1(numlines-i-1));
}
}
}
@ -1234,14 +1241,14 @@ static void P_LoadLineDefs(lumpnum_t lumpnum)
{
ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side
// cph - print a warning about the bug
CONS_Debug(DBG_SETUP, "P_LoadLineDefs: linedef %s missing first sidedef\n", sizeu1(numlines-i-1));
CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s missing first sidedef\n", sizeu1(numlines-i-1));
}
if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED))
{
ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side
// cph - print a warning about the bug
CONS_Debug(DBG_SETUP, "P_LoadLineDefs: linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1));
CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1));
}
if (ld->sidenum[0] != 0xffff && ld->special)
@ -1253,7 +1260,12 @@ static void P_LoadLineDefs(lumpnum_t lumpnum)
ld->polyobj = NULL;
#endif
}
}
static void P_LoadLineDefs(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawLineDefs(data, W_LumpLength(lumpnum));
Z_Free(data);
}
@ -1355,22 +1367,24 @@ static void P_LoadLineDefs2(void)
}
}
//
// P_LoadSideDefs
//
static inline void P_LoadSideDefs(lumpnum_t lumpnum)
static inline void P_LoadRawSideDefs(size_t i)
{
numsides = W_LumpLength(lumpnum) / sizeof (mapsidedef_t);
numsides = i / sizeof (mapsidedef_t);
if (numsides <= 0)
I_Error("Level has no sidedefs");
sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL);
}
// Delay loading texture names until after loaded linedefs.
static void P_LoadSideDefs2(lumpnum_t lumpnum)
static inline void P_LoadSideDefs(lumpnum_t lumpnum)
{
P_LoadRawSideDefs(W_LumpLength(lumpnum));
}
static void P_LoadRawSideDefs2(void *data)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
UINT16 i;
INT32 num;
@ -1388,7 +1402,7 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
if (sector_num >= numsectors)
{
CONS_Debug(DBG_SETUP, "P_LoadSideDefs2: sidedef %u has out-of-range sector num %u\n", i, sector_num);
CONS_Debug(DBG_SETUP, "P_LoadRawSideDefs2: sidedef %u has out-of-range sector num %u\n", i, sector_num);
sector_num = 0;
}
sd->sector = sec = &sectors[sector_num];
@ -1530,6 +1544,8 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
sd->text[6] = 0;
break;
}
case 4: // Speed pad parameters
case 414: // Play SFX
{
sd->toptexture = sd->midtexture = sd->bottomtexture = 0;
@ -1543,6 +1559,9 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
break;
}
case 9: // Mace parameters
case 14: // Bustable block parameters
case 15: // Fan particle spawner parameters
case 425: // Calls P_SetMobjState on calling mobj
case 434: // Custom Power
case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors
@ -1597,11 +1616,18 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
break;
}
}
Z_Free(data);
R_ClearTextureNumCache(true);
}
// Delay loading texture names until after loaded linedefs.
static void P_LoadSideDefs2(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawSideDefs2(data);
Z_Free(data);
}
static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, fixed_t bx1, fixed_t by1)
{
fixed_t bbox[4];
@ -1857,6 +1883,30 @@ static void P_CreateBlockMap(void)
}
}
// Split from P_LoadBlockMap for convenience
// -- Monster Iestyn 08/01/18
static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count)
{
size_t i;
blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, NULL);
// killough 3/1/98: Expand wad blockmap into larger internal one,
// by treating all offsets except -1 as unsigned and zero-extending
// them. This potentially doubles the size of blockmaps allowed,
// because Doom originally considered the offsets as always signed.
blockmaplump[0] = SHORT(wadblockmaplump[0]);
blockmaplump[1] = SHORT(wadblockmaplump[1]);
blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff;
blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff;
for (i = 4; i < count; i++)
{
INT16 t = SHORT(wadblockmaplump[i]); // killough 3/1/98
blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff;
}
}
//
// P_LoadBlockMap
//
@ -1883,38 +1933,20 @@ static boolean P_LoadBlockMap(lumpnum_t lumpnum)
return false;
{
size_t i;
INT16 *wadblockmaplump = malloc(count); //INT16 *wadblockmaplump = W_CacheLumpNum (lump, PU_LEVEL);
if (wadblockmaplump) W_ReadLump(lumpnum, wadblockmaplump);
else return false;
if (!wadblockmaplump)
return false;
W_ReadLump(lumpnum, wadblockmaplump);
count /= 2;
blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, 0);
// killough 3/1/98: Expand wad blockmap into larger internal one,
// by treating all offsets except -1 as unsigned and zero-extending
// them. This potentially doubles the size of blockmaps allowed,
// because Doom originally considered the offsets as always signed.
blockmaplump[0] = SHORT(wadblockmaplump[0]);
blockmaplump[1] = SHORT(wadblockmaplump[1]);
blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff;
blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff;
for (i = 4; i < count; i++)
{
INT16 t = SHORT(wadblockmaplump[i]); // killough 3/1/98
blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff;
}
P_ReadBlockMapLump(wadblockmaplump, count);
free(wadblockmaplump);
bmaporgx = blockmaplump[0]<<FRACBITS;
bmaporgy = blockmaplump[1]<<FRACBITS;
bmapwidth = blockmaplump[2];
bmapheight = blockmaplump[3];
}
bmaporgx = blockmaplump[0]<<FRACBITS;
bmaporgy = blockmaplump[1]<<FRACBITS;
bmapwidth = blockmaplump[2];
bmapheight = blockmaplump[3];
// clear out mobj chains
count = sizeof (*blocklinks)* bmapwidth*bmapheight;
blocklinks = Z_Calloc(count, PU_LEVEL, NULL);
@ -1948,6 +1980,53 @@ static boolean P_LoadBlockMap(lumpnum_t lumpnum)
#endif
}
// This needs to be a separate function
// because making both the WAD and PK3 loading code use
// the same functions is trickier than it looks for blockmap
// -- Monster Iestyn 09/01/18
static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname)
{
#if 0
(void)data;
(void)count;
(void)lumpname;
return false;
#else
// Check if the lump is named "BLOCKMAP"
if (!lumpname || memcmp(lumpname, "BLOCKMAP", 8) != 0)
{
CONS_Printf("No blockmap lump found for pk3!\n");
return false;
}
if (!count || count >= 0x20000)
return false;
CONS_Printf("Reading blockmap lump for pk3...\n");
// no need to malloc anything, assume the data is uncompressed for now
count /= 2;
P_ReadBlockMapLump((INT16 *)data, count);
bmaporgx = blockmaplump[0]<<FRACBITS;
bmaporgy = blockmaplump[1]<<FRACBITS;
bmapwidth = blockmaplump[2];
bmapheight = blockmaplump[3];
// clear out mobj chains
count = sizeof (*blocklinks)* bmapwidth*bmapheight;
blocklinks = Z_Calloc(count, PU_LEVEL, NULL);
blockmap = blockmaplump+4;
#ifdef POLYOBJECTS
// haleyjd 2/22/06: setup polyobject blockmap
count = sizeof(*polyblocklinks) * bmapwidth * bmapheight;
polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL);
#endif
return true;
#endif
}
//
// P_GroupLines
// Builds sector line lists and subsector sector numbers.
@ -2073,6 +2152,30 @@ static void P_LoadReject(lumpnum_t lumpnum)
rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
}
// PK3 version
// -- Monster Iestyn 09/01/18
static void P_LoadRawReject(UINT8 *data, size_t count, const char *lumpname)
{
// Check if the lump is named "REJECT"
if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0)
{
rejectmatrix = NULL;
CONS_Debug(DBG_SETUP, "P_LoadRawReject: No valid REJECT lump found\n");
return;
}
if (!count) // zero length, someone probably used ZDBSP
{
rejectmatrix = NULL;
CONS_Debug(DBG_SETUP, "P_LoadRawReject: REJECT lump has size 0, will not be loaded\n");
}
else
{
rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix
M_Memcpy(rejectmatrix, data, count); // copy the data into it
}
}
#if 0
static char *levellumps[] =
{
@ -2252,7 +2355,16 @@ void P_LoadThingsOnly(void)
P_LevelInitStuff();
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can use the things lump
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
fileinfo += ML_THINGS; // we only need the THINGS lump
P_PrepareRawThings(wadData + fileinfo->filepos, fileinfo->size);
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
P_LoadThings();
P_SpawnSecretItems(true);
@ -2690,7 +2802,12 @@ boolean P_SetupLevel(boolean skipprecip)
}
// internal game map
lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap));
maplumpname = G_BuildMapName(gamemap);
//lastloadedmaplumpnum = LUMPERROR;
lastloadedmaplumpnum = W_CheckNumForName(maplumpname);
if (lastloadedmaplumpnum == INT16_MAX)
I_Error("Map %s not found.\n", maplumpname);
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
CON_SetupBackColormap();
@ -2700,38 +2817,93 @@ boolean P_SetupLevel(boolean skipprecip)
P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5);
// note: most of this ordering is important
loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP);
// HACK ALERT: Cache the WAD, get the map data into the tables, free memory.
// As it is implemented right now, we're assuming an uncompressed WAD.
// (As in, a normal PWAD, not ZWAD or anything. The lump itself can be compressed.)
// We're not accounting for extra lumps and scrambled lump positions. Any additional data will cause an error.
if (W_IsLumpWad(lastloadedmaplumpnum))
{
// Remember that we're assuming that the WAD will have a specific set of lumps in a specific order.
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
//filelump_t *fileinfo = wadData + ((wadinfo_t *)wadData)->infotableofs;
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
UINT32 numlumps = ((wadinfo_t *)wadData)->numlumps;
P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES);
P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS);
if (numlumps < ML_REJECT) // at least 9 lumps should be in the wad for a map to be loaded
{
I_Error("Bad WAD file for map %s!\n", maplumpname);
}
P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS);
if (numlumps > ML_BLOCKMAP) // enough room for a BLOCKMAP lump at least
{
loadedbm = P_LoadRawBlockMap(
wadData + (fileinfo + ML_BLOCKMAP)->filepos,
(fileinfo + ML_BLOCKMAP)->size,
(fileinfo + ML_BLOCKMAP)->name);
}
P_LoadRawVertexes(wadData + (fileinfo + ML_VERTEXES)->filepos, (fileinfo + ML_VERTEXES)->size);
P_LoadRawSectors(wadData + (fileinfo + ML_SECTORS)->filepos, (fileinfo + ML_SECTORS)->size);
P_LoadRawSideDefs((fileinfo + ML_SIDEDEFS)->size);
P_LoadRawLineDefs(wadData + (fileinfo + ML_LINEDEFS)->filepos, (fileinfo + ML_LINEDEFS)->size);
P_LoadRawSideDefs2(wadData + (fileinfo + ML_SIDEDEFS)->filepos);
P_LoadRawSubsectors(wadData + (fileinfo + ML_SSECTORS)->filepos, (fileinfo + ML_SSECTORS)->size);
P_LoadRawNodes(wadData + (fileinfo + ML_NODES)->filepos, (fileinfo + ML_NODES)->size);
P_LoadRawSegs(wadData + (fileinfo + ML_SEGS)->filepos, (fileinfo + ML_SEGS)->size);
if (numlumps > ML_REJECT) // enough room for a REJECT lump at least
{
P_LoadRawReject(
wadData + (fileinfo + ML_REJECT)->filepos,
(fileinfo + ML_REJECT)->size,
(fileinfo + ML_REJECT)->name);
}
P_LoadLineDefs(lastloadedmaplumpnum + ML_LINEDEFS);
if (!loadedbm)
P_CreateBlockMap(); // Graue 02-29-2004
P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS);
// Important: take care of the ordering of the next functions.
if (!loadedbm)
P_CreateBlockMap(); // Graue 02-29-2004
P_LoadLineDefs2();
P_GroupLines();
numdmstarts = numredctfstarts = numbluectfstarts = 0;
P_LoadLineDefs2();
P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS);
P_LoadNodes(lastloadedmaplumpnum + ML_NODES);
P_LoadSegs(lastloadedmaplumpnum + ML_SEGS);
P_LoadReject(lastloadedmaplumpnum + ML_REJECT);
P_GroupLines();
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
P_MapStart();
numdmstarts = numredctfstarts = numbluectfstarts = 0;
P_PrepareRawThings(wadData + (fileinfo + ML_THINGS)->filepos, (fileinfo + ML_THINGS)->size);
Z_Free(wadData);
}
else
{
// Important: take care of the ordering of the next functions.
loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP);
P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES);
P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS);
P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS);
P_LoadLineDefs(lastloadedmaplumpnum + ML_LINEDEFS);
P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS);
P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS);
P_LoadNodes(lastloadedmaplumpnum + ML_NODES);
P_LoadSegs(lastloadedmaplumpnum + ML_SEGS);
P_LoadReject(lastloadedmaplumpnum + ML_REJECT);
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = NULL;
// Important: take care of the ordering of the next functions.
if (!loadedbm)
P_CreateBlockMap(); // Graue 02-29-2004
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
P_LoadLineDefs2();
P_GroupLines();
numdmstarts = numredctfstarts = numbluectfstarts = 0;
P_MapStart();
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
P_MapStart();
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
}
#ifdef ESLOPE
P_ResetDynamicSlopes();
@ -2979,7 +3151,7 @@ boolean P_RunSOC(const char *socfilename)
lumpnum_t lump;
if (strstr(socfilename, ".soc") != NULL)
return P_AddWadFile(socfilename, NULL);
return P_AddWadFile(socfilename);
lump = W_CheckNumForName(socfilename);
if (lump == LUMPERROR)
@ -2995,17 +3167,17 @@ boolean P_RunSOC(const char *socfilename)
// Add a wadfile to the active wad files,
// replace sounds, musics, patches, textures, sprites and maps
//
boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
boolean P_AddWadFile(const char *wadfilename)
{
size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
UINT16 numlumps, wadnum;
INT16 firstmapreplaced = 0, num;
char *name;
lumpinfo_t *lumpinfo;
boolean texturechange = false;
boolean mapsadded = false;
boolean replacedcurrentmap = false;
if ((numlumps = W_LoadWadFile(wadfilename)) == INT16_MAX)
if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename);
@ -3062,6 +3234,7 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
if (!devparm && digmreplaces)
CONS_Printf(M_GetText("%s digital musics replaced\n"), sizeu1(digmreplaces));
//
// search for sprite replacements
//
@ -3096,10 +3269,10 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
for (i = 0; i < numlumps; i++, lumpinfo++)
{
name = lumpinfo->name;
num = firstmapreplaced;
if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers
{
INT16 num;
if (name[5]!='\0')
continue;
num = (INT16)M_MapNumber(name[3], name[4]);
@ -3109,16 +3282,10 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
replacedcurrentmap = true;
CONS_Printf("%s\n", name);
}
if (num && (num < firstmapreplaced || !firstmapreplaced))
{
firstmapreplaced = num;
if (firstmapname)
*firstmapname = name;
mapsadded = true;
}
}
if (!firstmapreplaced)
if (!mapsadded)
CONS_Printf(M_GetText("No maps added\n"));
// reload status bar (warning should have valid player!)

View File

@ -59,7 +59,7 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif
void P_LoadThingsOnly(void);
boolean P_SetupLevel(boolean skipprecip);
boolean P_AddWadFile(const char *wadfilename, char **firstmapname);
boolean P_AddWadFile(const char *wadfilename);
#ifdef DELFILE
boolean P_DelWadFile(void);
#endif

View File

@ -29,7 +29,7 @@ static pslope_t *slopelist = NULL;
static UINT16 slopecount = 0;
// Calculate line normal
static void P_CalculateSlopeNormal(pslope_t *slope) {
void P_CalculateSlopeNormal(pslope_t *slope) {
slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT);
slope->normal.x = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x);
slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y);

View File

@ -14,6 +14,7 @@
#define P_SLOPES_H__
#ifdef ESLOPE
void P_CalculateSlopeNormal(pslope_t *slope);
void P_ResetDynamicSlopes(void);
void P_RunDynamicSlopes(void);
// P_SpawnSlope_Line

View File

@ -279,10 +279,13 @@ void P_InitPicAnims(void)
Z_Free(animatedLump);
}
// Now find ANIMDEFS
// Find ANIMDEFS lump in the WAD
animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0);
if (animdefsLumpNum != INT16_MAX)
while (animdefsLumpNum != INT16_MAX)
{
P_ParseANIMDEFSLump(w, animdefsLumpNum);
animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", (UINT16)w, animdefsLumpNum + 1);
}
}
// Define the last one
animdefs[maxanims].istexture = -1;
@ -6243,9 +6246,21 @@ void P_SpawnSpecials(INT32 fromnetsave)
case 259: // Make-Your-Own FOF!
if (lines[i].sidenum[1] != 0xffff)
{
UINT8 *data = W_CacheLumpNum(lastloadedmaplumpnum + ML_SIDEDEFS,PU_STATIC);
UINT8 *data;
UINT16 b;
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can get the data from the sidedefs lump
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
fileinfo += ML_SIDEDEFS; // we only need the SIDEDEFS lump
data = Z_Malloc(fileinfo->size, PU_STATIC, NULL);
M_Memcpy(data, wadData + fileinfo->filepos, fileinfo->size); // copy data
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
data = W_CacheLumpNum(lastloadedmaplumpnum + ML_SIDEDEFS,PU_STATIC);
for (b = 0; b < (INT16)numsides; b++)
{
register mapsidedef_t *msd = (mapsidedef_t *)data + b;
@ -6614,6 +6629,7 @@ void T_Scroll(scroll_t *s)
line_t *line;
size_t i;
INT32 sect;
ffloor_t *rover;
case sc_side: // scroll wall texture
side = sides + s->affectee;
@ -6655,6 +6671,19 @@ void T_Scroll(scroll_t *s)
sector_t *psec;
psec = sectors + sect;
// Find the FOF corresponding to the control linedef
for (rover = psec->ffloors; rover; rover = rover->next)
{
if (rover->master == sec->lines[i])
break;
}
if (!rover) // This should be impossible, but don't complain if it is the case somehow
continue;
if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there
continue;
for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
@ -6718,6 +6747,19 @@ void T_Scroll(scroll_t *s)
sector_t *psec;
psec = sectors + sect;
// Find the FOF corresponding to the control linedef
for (rover = psec->ffloors; rover; rover = rover->next)
{
if (rover->master == sec->lines[i])
break;
}
if (!rover) // This should be impossible, but don't complain if it is the case somehow
continue;
if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there
continue;
for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
{
thing = node->m_thing;

View File

@ -607,7 +607,8 @@ void P_Ticker(boolean run)
}
// Keep track of how long they've been playing!
totalplaytime++;
if (!demoplayback) // Don't increment if a demo is playing.
totalplaytime++;
if (!useNightsSS && G_IsSpecialStage(gamemap))
P_DoSpecialStageStuff();

View File

@ -1621,6 +1621,9 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
for (rover = sector->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS))
continue;
if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL)
continue;
#ifdef ESLOPE
@ -1835,6 +1838,12 @@ static void P_CheckBouncySectors(player_t *player)
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS))
continue; // FOFs should not be bouncy if they don't even "exist"
if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 15)
continue; // this sector type is required for FOFs to be bouncy
topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
@ -1848,7 +1857,6 @@ static void P_CheckBouncySectors(player_t *player)
&& oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL))
top = false;
if (GETSECSPECIAL(rover->master->frontsector->special, 1) == 15)
{
fixed_t linedist;
@ -7845,7 +7853,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
subsector_t *newsubsec;
fixed_t f1, f2;
cameranoclip = (player->pflags & (PF_NOCLIP|PF_NIGHTSMODE)) || (player->mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!!
// We probably shouldn't move the camera if there is no player or player mobj somehow
if (!player || !player->mo)
return true;
mo = player->mo;
cameranoclip = (player->pflags & (PF_NOCLIP|PF_NIGHTSMODE)) || (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!!
if (!(player->climbing || (player->pflags & PF_NIGHTSMODE) || player->playerstate == PST_DEAD))
{
@ -7866,7 +7880,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
else if (player == &players[secondarydisplayplayer])
focusangle = localangle2;
else
focusangle = player->mo->angle;
focusangle = mo->angle;
if (thiscam == &camera)
camrotate = cv_cam_rotate.value;
else if (thiscam == &camera2)
@ -7878,17 +7892,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
return true;
}
if (!player || !player->mo)
return true;
mo = player->mo;
thiscam->radius = FixedMul(20*FRACUNIT, mo->scale);
thiscam->height = FixedMul(16*FRACUNIT, mo->scale);
if (!mo)
return true;
// Don't run while respawning from a starpost
// Inu 4/8/13 Why not?!
// if (leveltime > 0 && timeinmap <= 0)
@ -7896,7 +7902,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (player->pflags & PF_NIGHTSMODE)
{
focusangle = player->mo->angle;
focusangle = mo->angle;
focusaiming = 0;
}
else if (player == &players[consoleplayer])
@ -7911,7 +7917,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
}
else
{
focusangle = player->mo->angle;
focusangle = mo->angle;
focusaiming = player->aiming;
}
@ -7958,12 +7964,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
angle = R_PointToAngle2(player->axis1->x, player->axis1->y, player->axis2->x, player->axis2->y);
angle += ANGLE_90;
}
else if (player->mo->target)
else if (mo->target)
{
if (player->mo->target->flags & MF_AMBUSH)
angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y);
if (mo->target->flags & MF_AMBUSH)
angle = R_PointToAngle2(mo->target->x, mo->target->y, mo->x, mo->y);
else
angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->target->x, player->mo->target->y);
angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y);
}
}
else if (P_AnalogMove(player)) // Analog
@ -8058,7 +8064,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (twodlevel || (mo->flags2 & MF2_TWOD))
{
// Camera doesn't ALWAYS need to move, only when running...
if (abs(player->mo->momx) > 10)
if (abs(mo->momx) > 10)
{
// Move the camera all smooth-like, not jerk it around...
if (mo->momx > 0)
@ -8366,19 +8372,19 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (!(multiplayer || netgame) && !splitscreen)
{
fixed_t vx = thiscam->x, vy = thiscam->y;
if (player->awayviewtics && player->awayviewmobj != NULL) // Camera must obviously exist
if (player->awayviewtics && player->awayviewmobj != NULL && !P_MobjWasRemoved(player->awayviewmobj)) // Camera must obviously exist
{
vx = player->awayviewmobj->x;
vy = player->awayviewmobj->y;
}
if (P_AproxDistance(vx - player->mo->x, vy - player->mo->y) < FixedMul(48*FRACUNIT, mo->scale))
player->mo->flags2 |= MF2_SHADOW;
if (P_AproxDistance(vx - mo->x, vy - mo->y) < FixedMul(48*FRACUNIT, mo->scale))
mo->flags2 |= MF2_SHADOW;
else
player->mo->flags2 &= ~MF2_SHADOW;
mo->flags2 &= ~MF2_SHADOW;
}
else
player->mo->flags2 &= ~MF2_SHADOW;
mo->flags2 &= ~MF2_SHADOW;
/* if (!resetcalled && (player->pflags & PF_NIGHTSMODE && player->exiting))
{
@ -8528,7 +8534,7 @@ static void P_CalcPostImg(player_t *player)
else
pviewheight = player->mo->z + player->viewheight;
if (player->awayviewtics)
if (player->awayviewtics && player->awayviewmobj && !P_MobjWasRemoved(player->awayviewmobj))
{
sector = player->awayviewmobj->subsector->sector;
pviewheight = player->awayviewmobj->z + 20*FRACUNIT;
@ -8695,6 +8701,13 @@ void P_PlayerThink(player_t *player)
}
}
#endif
if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj))
{
P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid
player->awayviewtics = 0; // reset to zero
}
if (player->pflags & PF_GLIDING)
{
if (player->panim != PA_ABILITY)

View File

@ -365,8 +365,8 @@ void R_FlushTextureCache(void)
}
// Need these prototypes for later; defining them here instead of r_data.h so they're "private"
int R_CountTexturesInTEXTURESLump(UINT16 wadNum);
void R_ParseTEXTURESLump(UINT16 wadNum, INT32 *index);
int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum);
void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *index);
//
// R_LoadTextures
@ -404,13 +404,22 @@ void R_LoadTextures(void)
// but the alternative is to spend a ton of time checking and re-checking all previous entries just to skip any potentially patched textures.
for (w = 0, numtextures = 0; w < numwadfiles; w++)
{
texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1;
texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0);
texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0);
if (texturesLumpPos != INT16_MAX)
if (wadfiles[w]->type == RET_PK3)
{
numtextures += R_CountTexturesInTEXTURESLump((UINT16)w);
texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
}
else
{
texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1;
texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0);
}
texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0);
while (texturesLumpPos != INT16_MAX)
{
numtextures += R_CountTexturesInTEXTURESLump((UINT16)w, (UINT16)texturesLumpPos);
texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1);
}
// Add all the textures between TX_START and TX_END
@ -447,12 +456,25 @@ void R_LoadTextures(void)
for (i = 0, w = 0; w < numwadfiles; w++)
{
// Get the lump numbers for the markers in the WAD, if they exist.
texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1;
texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0);
texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0);
if (texturesLumpPos != INT16_MAX)
R_ParseTEXTURESLump(w,&i);
if (wadfiles[w]->type == RET_PK3)
{
texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0);
while (texturesLumpPos != INT16_MAX)
{
R_ParseTEXTURESLump(w, texturesLumpPos, &i);
texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1);
}
}
else
{
texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1;
texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0);
texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0);
if (texturesLumpPos != INT16_MAX)
R_ParseTEXTURESLump(w, texturesLumpPos, &i);
}
if (texstart == INT16_MAX || texend == INT16_MAX)
continue;
@ -472,40 +494,22 @@ void R_LoadTextures(void)
}
else
{
UINT16 patchcount = 1;
//CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height);
if (SHORT(patchlump->width) == 64
&& SHORT(patchlump->height) == 64)
{ // 64x64 patch
const column_t *column;
for (k = 0; k < SHORT(patchlump->width); k++)
{ // Find use of transparency.
column = (const column_t *)((const UINT8 *)patchlump + LONG(patchlump->columnofs[k]));
if (column->length != SHORT(patchlump->height))
break;
}
if (k == SHORT(patchlump->width))
patchcount = 2; // No transparency? 64x128 texture.
}
texture = textures[i] = Z_Calloc(sizeof(texture_t) + (sizeof(texpatch_t) * patchcount), PU_STATIC, NULL);
texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);
// Set texture properties.
M_Memcpy(texture->name, W_CheckNameForNumPwad((UINT16)w, texstart + j), sizeof(texture->name));
texture->width = SHORT(patchlump->width);
texture->height = SHORT(patchlump->height)*patchcount;
texture->patchcount = patchcount;
texture->height = SHORT(patchlump->height);
texture->patchcount = 1;
texture->holes = false;
// Allocate information for the texture's patches.
for (k = 0; k < patchcount; k++)
{
patch = &texture->patches[k];
patch = &texture->patches[0];
patch->originx = 0;
patch->originy = (INT16)(k*patchlump->height);
patch->wad = (UINT16)w;
patch->lump = texstart + j;
}
patch->originx = patch->originy = 0;
patch->wad = (UINT16)w;
patch->lump = texstart + j;
Z_Unlock(patchlump);
@ -817,7 +821,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture)
}
// Parses the TEXTURES lump... but just to count the number of textures.
int R_CountTexturesInTEXTURESLump(UINT16 wadNum)
int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum)
{
char *texturesLump;
size_t texturesLumpLength;
@ -828,11 +832,11 @@ int R_CountTexturesInTEXTURESLump(UINT16 wadNum)
// Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll
// need to make a space of memory where I can ensure that it will terminate
// correctly. Start by loading the relevant data from the WAD.
texturesLump = (char *)W_CacheLumpNumPwad(wadNum,W_CheckNumForNamePwad("TEXTURES", wadNum, 0),PU_STATIC);
texturesLump = (char *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC);
// If that didn't exist, we have nothing to do here.
if (texturesLump == NULL) return 0;
// If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly.
texturesLumpLength = W_LumpLengthPwad(wadNum,W_CheckNumForNamePwad("TEXTURES",wadNum,0));
texturesLumpLength = W_LumpLengthPwad(wadNum, lumpNum);
texturesText = (char *)Z_Malloc((texturesLumpLength+1)*sizeof(char),PU_STATIC,NULL);
// Now move the contents of the lump into this new location.
memmove(texturesText,texturesLump,texturesLumpLength);
@ -864,7 +868,7 @@ int R_CountTexturesInTEXTURESLump(UINT16 wadNum)
}
// Parses the TEXTURES lump... for real, this time.
void R_ParseTEXTURESLump(UINT16 wadNum, INT32 *texindex)
void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *texindex)
{
char *texturesLump;
size_t texturesLumpLength;
@ -877,11 +881,11 @@ void R_ParseTEXTURESLump(UINT16 wadNum, INT32 *texindex)
// Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll
// need to make a space of memory where I can ensure that it will terminate
// correctly. Start by loading the relevant data from the WAD.
texturesLump = (char *)W_CacheLumpNumPwad(wadNum,W_CheckNumForNamePwad("TEXTURES", wadNum, 0),PU_STATIC);
texturesLump = (char *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC);
// If that didn't exist, we have nothing to do here.
if (texturesLump == NULL) return;
// If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly.
texturesLumpLength = W_LumpLengthPwad(wadNum,W_CheckNumForNamePwad("TEXTURES",wadNum,0));
texturesLumpLength = W_LumpLengthPwad(wadNum, lumpNum);
texturesText = (char *)Z_Malloc((texturesLumpLength+1)*sizeof(char),PU_STATIC,NULL);
// Now move the contents of the lump into this new location.
memmove(texturesText,texturesLump,texturesLumpLength);
@ -968,12 +972,51 @@ static void R_InitExtraColormaps(void)
CONS_Printf(M_GetText("Number of Extra Colormaps: %s\n"), sizeu1(numcolormaplumps));
}
// 12/14/14 -- only take flats in F_START/F_END
// Search for flat name.
lumpnum_t R_GetFlatNumForName(const char *name)
{
lumpnum_t lump = W_CheckNumForNameInBlock(name, "F_START", "F_END");
if (lump == LUMPERROR)
lump = W_CheckNumForNameInBlock(name, "FF_START", "FF_END"); // deutex, some other old things
INT32 i;
lumpnum_t lump;
lumpnum_t start;
lumpnum_t end;
// Scan wad files backwards so patched flats take preference.
for (i = numwadfiles - 1; i >= 0; i--)
{
switch (wadfiles[i]->type)
{
case RET_WAD:
if ((start = W_CheckNumForNamePwad("F_START", (UINT16)i, 0)) == INT16_MAX)
{
if ((start = W_CheckNumForNamePwad("FF_START", (UINT16)i, 0)) == INT16_MAX)
continue;
else if ((end = W_CheckNumForNamePwad("FF_END", (UINT16)i, start)) == INT16_MAX)
continue;
}
else
if ((end = W_CheckNumForNamePwad("F_END", (UINT16)i, start)) == INT16_MAX)
continue;
break;
case RET_PK3:
if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX)
continue;
if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX)
continue;
break;
default:
continue;
}
// Now find lump with specified name in that range.
lump = W_CheckNumForNamePwad(name, (UINT16)i, start);
if (lump < end)
{
lump += (i<<16); // found it, in our constraints
break;
}
lump = LUMPERROR;
}
if (lump == LUMPERROR)
{
if (strcmp(name, SKYFLATNAME))

View File

@ -327,21 +327,28 @@ void R_AddSpriteDefs(UINT16 wadnum)
UINT16 start, end;
char wadname[MAX_WADPATH];
// find the sprites section in this pwad
// we need at least the S_END
// (not really, but for speedup)
switch (wadfiles[wadnum]->type)
{
case RET_WAD:
start = W_CheckNumForNamePwad("S_START", wadnum, 0);
if (start == INT16_MAX)
start = W_CheckNumForNamePwad("SS_START", wadnum, 0); //deutex compatib.
if (start == INT16_MAX)
start = 0; //let say S_START is lump 0
else
start++; // just after S_START
end = W_CheckNumForNamePwad("S_END",wadnum,start);
if (end == INT16_MAX)
end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib.
break;
case RET_PK3:
start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0);
end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start);
break;
default:
return;
}
start = W_CheckNumForNamePwad("S_START", wadnum, 0);
if (start == INT16_MAX)
start = W_CheckNumForNamePwad("SS_START", wadnum, 0); //deutex compatib.
if (start == INT16_MAX)
start = 0; //let say S_START is lump 0
else
start++; // just after S_START
end = W_CheckNumForNamePwad("S_END",wadnum,start);
if (end == INT16_MAX)
end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib.
if (end == INT16_MAX)
{
CONS_Debug(DBG_SETUP, "no sprites in pwad %d\n", wadnum);
@ -2441,7 +2448,7 @@ void SetPlayerSkin(INT32 playernum, const char *skinname)
if (P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname);
else if(server || adminplayer == consoleplayer)
else if(server || IsPlayerAdmin(consoleplayer))
CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname);
SetPlayerSkinByNum(playernum, 0);
@ -2499,7 +2506,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
if (P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Skin %d not found\n"), skinnum);
else if(server || adminplayer == consoleplayer)
else if(server || IsPlayerAdmin(consoleplayer))
CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum);
SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin
}

View File

@ -297,6 +297,7 @@
</ClCompile>
<ClCompile Include="..\i_tcp.c" />
<ClCompile Include="..\lua_baselib.c" />
<ClCompile Include="..\lua_blockmaplib.c" />
<ClCompile Include="..\lua_consolelib.c" />
<ClCompile Include="..\lua_hooklib.c" />
<ClCompile Include="..\lua_hudlib.c" />

View File

@ -639,6 +639,9 @@
<ClCompile Include="..\lua_baselib.c">
<Filter>LUA</Filter>
</ClCompile>
<ClCompile Include="..\lua_blockmaplib.c">
<Filter>LUA</Filter>
</ClCompile>
<ClCompile Include="..\lua_consolelib.c">
<Filter>LUA</Filter>
</ClCompile>

View File

@ -894,8 +894,8 @@ void I_GetJoystickEvents(void)
UINT64 joyhats = 0;
#if 0
UINT64 joybuttons = 0;
#endif
Sint16 axisx, axisy;
#endif
if (!joystick_started) return;
@ -963,6 +963,7 @@ void I_GetJoystickEvents(void)
}
}
#if 0
// send joystick axis positions
event.type = ev_joystick;
@ -1013,6 +1014,7 @@ void I_GetJoystickEvents(void)
}
D_PostEvent(&event);
}
#endif
}
/** \brief Open joystick handle
@ -1176,8 +1178,8 @@ void I_GetJoystick2Events(void)
UINT64 joyhats = 0;
#if 0
INT64 joybuttons = 0;
#endif
INT32 axisx, axisy;
#endif
if (!joystick2_started)
return;
@ -1247,6 +1249,7 @@ void I_GetJoystick2Events(void)
}
}
#if 0
// send joystick axis positions
event.type = ev_joystick2;
@ -1297,7 +1300,7 @@ void I_GetJoystick2Events(void)
}
D_PostEvent(&event);
}
#endif
}
/** \brief Open joystick handle

View File

@ -767,6 +767,33 @@ static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt)
D_PostEvent(&event);
}
#if 0
static void Impl_HandleJoystickHatEvent(SDL_JoyHatEvent evt)
{
event_t event;
SDL_JoystickID joyid[2];
// Determine the Joystick IDs for each current open joystick
joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev);
joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev);
if (evt.hat >= JOYHATS)
return; // ignore hats with too high an index
if (evt.which == joyid[0])
{
event.data1 = KEY_HAT1 + (evt.hat*4);
}
else if (evt.which == joyid[1])
{
event.data1 = KEY_2HAT1 + (evt.hat*4);
}
else return;
// NOTE: UNFINISHED
}
#endif
static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
{
event_t event;
@ -804,6 +831,8 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
if (event.type != ev_console) D_PostEvent(&event);
}
void I_GetEvent(void)
{
SDL_Event evt;
@ -844,6 +873,11 @@ void I_GetEvent(void)
case SDL_JOYAXISMOTION:
Impl_HandleJoystickAxisEvent(evt.jaxis);
break;
#if 0
case SDL_JOYHATMOTION:
Impl_HandleJoystickHatEvent(evt.jhat)
break;
#endif
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
Impl_HandleJoystickButtonEvent(evt.jbutton, evt.type);

View File

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.20;
CURRENT_PROJECT_VERSION = 2.1.21;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.20;
CURRENT_PROJECT_VERSION = 2.1.21;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = (

View File

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.20;
CURRENT_PROJECT_VERSION = 2.1.21;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.20;
CURRENT_PROJECT_VERSION = 2.1.21;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = (

View File

@ -1871,12 +1871,12 @@ static void ST_overlayDrawer(void)
if (!hu_showscores && !splitscreen && netgame && displayplayer == consoleplayer)
{
if (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1)
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), 0, M_GetText("Press F12 to watch another player."));
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), 0, M_GetText("Press Viewpoint Key to watch a player."));
else if (gametype == GT_HIDEANDSEEK &&
(!stplyr->spectator && !(stplyr->pflags & PF_TAGIT)) && (leveltime > hidetime * TICRATE))
{
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(116), 0, M_GetText("You cannot move while hiding."));
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), 0, M_GetText("Press F12 to watch another player."));
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), 0, M_GetText("Press Viewpoint Key to watch a player."));
}
else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text.
{
@ -1899,7 +1899,7 @@ static void ST_overlayDrawer(void)
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("You cannot join the game until the stage has ended."));
else
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Fire to enter the game."));
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(148), V_HUDTRANSHALF, M_GetText("Press F12 to watch another player."));
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(148), V_HUDTRANSHALF, M_GetText("Press Viewpoint Key to watch a player."));
V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(164), V_HUDTRANSHALF, M_GetText("Press Jump to float and Spin to sink."));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,22 @@
#pragma interface
#endif
// a raw entry of the wad directory
// NOTE: This sits here and not in w_wad.c because p_setup.c makes use of it to load map WADs inside PK3s.
#if defined(_MSC_VER)
#pragma pack(1)
#endif
typedef struct
{
UINT32 filepos; // file offset of the resource
UINT32 size; // size of the resource
char name[8]; // name of the resource
} ATTRPACK filelump_t;
#if defined(_MSC_VER)
#pragma pack()
#endif
// ==============================================================
// WAD FILE STRUCTURE DEFINITIONS
// ==============================================================
@ -34,14 +50,26 @@ typedef struct
UINT32 infotableofs; // the 'directory' of resources
} wadinfo_t;
// Available compression methods for lumps.
typedef enum
{
CM_NOCOMPRESSION,
#ifdef HAVE_ZLIB
CM_DEFLATE,
#endif
CM_LZF,
CM_UNSUPPORTED
} compmethod;
// a memory entry of the wad directory
typedef struct
{
unsigned long position; // filelump_t filepos
unsigned long disksize; // filelump_t size
char name[9]; // filelump_t name[]
char *name2; // Used by PK3s. Dynamically allocated name.
size_t size; // real (uncompressed) size
INT32 compressed; // i
compmethod compression; // lump compression method
} lumpinfo_t;
// =========================================================================
@ -58,9 +86,21 @@ typedef struct
#include "m_aatree.h"
#endif
// Resource type of the WAD. Yeah, I know this sounds dumb, but I'll leave it like this until I clean up the code further.
typedef enum restype
{
RET_WAD,
RET_SOC,
RET_LUA,
RET_PK3,
RET_UNKNOWN,
} restype_t;
typedef struct wadfile_s
{
char *filename;
restype_t type;
lumpinfo_t *lumpinfo;
lumpcache_t *lumpcache;
#ifdef HWRENDER
@ -86,7 +126,7 @@ void W_Shutdown(void);
// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened
FILE *W_OpenWadFile(const char **filename, boolean useerrors);
// Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
UINT16 W_LoadWadFile(const char *filename);
UINT16 W_InitFile(const char *filename);
#ifdef DELFILE
void W_UnloadWadFile(UINT16 num);
#endif
@ -99,6 +139,12 @@ const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
const char *W_CheckNameForNum(lumpnum_t lumpnum);
UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad
UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump);
lumpnum_t W_CheckNumForMap(const char *name);
lumpnum_t W_CheckNumForName(const char *name);
lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR
lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend);
@ -107,6 +153,12 @@ UINT8 W_LumpExists(const char *name); // Lua uses this.
size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump);
size_t W_LumpLength(lumpnum_t lumpnum);
boolean W_IsLumpWad(lumpnum_t lumpnum); // for loading maps from WADs in PK3s
#ifdef HAVE_ZLIB
void zerr(int ret); // zlib error checking
#endif
size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset);
size_t W_ReadLumpHeader(lumpnum_t lump, void *dest, size_t size, size_t offest); // read all or a part of a lump
void W_ReadLumpPwad(UINT16 wad, UINT16 lump, void *dest);

View File

@ -132,6 +132,7 @@
</ClCompile>
<ClCompile Include="..\i_tcp.c" />
<ClCompile Include="..\lua_baselib.c" />
<ClCompile Include="..\lua_blockmaplib.c" />
<ClCompile Include="..\lua_consolelib.c" />
<ClCompile Include="..\lua_hooklib.c" />
<ClCompile Include="..\lua_hudlib.c" />

View File

@ -228,6 +228,9 @@
<ClCompile Include="..\lua_baselib.c">
<Filter>LUA</Filter>
</ClCompile>
<ClCompile Include="..\lua_blockmaplib.c">
<Filter>LUA</Filter>
</ClCompile>
<ClCompile Include="..\lua_consolelib.c">
<Filter>LUA</Filter>
</ClCompile>

View File

@ -1796,37 +1796,6 @@ void Y_EndIntermission(void)
usebuffer = false;
}
//
// Y_EndGame
//
// Why end the game?
// Because Y_FollowIntermission and F_EndCutscene would
// both do this exact same thing *in different ways* otherwise,
// which made it so that you could only unlock Ultimate mode
// if you had a cutscene after the final level and crap like that.
// This function simplifies it so only one place has to be updated
// when something new is added.
void Y_EndGame(void)
{
// Only do evaluation and credits in coop games.
if (gametype == GT_COOP)
{
if (nextmap == 1102-1) // end game with credits
{
F_StartCredits();
return;
}
if (nextmap == 1101-1) // end game with evaluation
{
F_StartGameEvaluation();
return;
}
}
// 1100 or competitive multiplayer, so go back to title screen.
D_StartTitle();
}
//
// Y_FollowIntermission
//
@ -1838,21 +1807,10 @@ static void Y_FollowIntermission(void)
return;
}
if (nextmap < 1100-1)
{
// normal level
G_AfterIntermission();
return;
}
// Start a custom cutscene if there is one.
if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking)
{
F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false);
return;
}
Y_EndGame();
// This handles whether to play a post-level cutscene, end the game,
// or simply go to the next level.
// No need to duplicate the code here!
G_AfterIntermission();
}
#define UNLOAD(x) Z_ChangeTag(x, PU_CACHE); x = NULL

View File

@ -15,7 +15,6 @@ void Y_IntermissionDrawer(void);
void Y_Ticker(void);
void Y_StartIntermission(void);
void Y_EndIntermission(void);
void Y_EndGame(void);
typedef enum
{

View File

@ -1,10 +0,0 @@
*
*.*
!staging
!sfx
!uninstaller
!! MAKE SURE FILES ARE IN new-install ARCHIVE FOLDER !.txt
!BuildInstaller.bat
!README.txt
!VersionFileName.txt
!.gitignore

View File

@ -1,76 +0,0 @@
@echo off
set "SCRIPTDIR=%~dp0"
set "SCRIPTDIR=%SCRIPTDIR:~0,-1%"
IF [%SRB2VERSIONNAME%] == [] set /p SRB2VERSIONNAME=<"%SCRIPTDIR%\VersionFileName.txt"
:: Find 7z
set SVZIP=
if NOT [%1] == [] (
echo.%~1 | findstr /C:"7z" 1>nul
if NOT errorlevel 1 (
if exist "%~1" set "SVZIP=%~1"
)
)
if ["%SVZIP%"] == [""] (
if exist "%ProgramFiles(x86)%\7-Zip\7z.exe" set "SVZIP=%ProgramFiles(x86)%\7-Zip\7z.exe"
if exist "%ProgramFiles%\7-Zip\7z.exe" set "SVZIP=%ProgramFiles%\7-Zip\7z.exe"
if exist "%ProgramW6432%\7-Zip\7z.exe" set "SVZIP=%ProgramW6432%\7-Zip\7z.exe"
)
:: Is it in PATH?
if ["%SVZIP%"] == [""] (
"7z.exe" --help > NUL 2> NUL
if NOT errorlevel 1 (
set "SVZIP=7z.exe"
)
)
:: Create the uninstaller
if NOT ["%SVZIP%"] == [""] (
del /f /q "%SCRIPTDIR%\Uninstaller.7z" 2> NUL
"%SVZIP%" a -t7z "%SCRIPTDIR%\Uninstaller.7z" "%SCRIPTDIR%\uninstaller\*" -m5=LZMA2
copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-uninstaller.txt" + "%SCRIPTDIR%\Uninstaller.7z" "%SCRIPTDIR%\staging\new-install\uninstall.exe"
del /f /q "%SCRIPTDIR%\uninstaller.7z"
)
:: Operate on install archives
type NUL > "%SCRIPTDIR%\staging\new-install\staging.txt"
if exist "%SCRIPTDIR%\Installer.7z" (
if NOT ["%SVZIP%"] == [""] (
"%SVZIP%" a "%SCRIPTDIR%\Installer.7z" "%SCRIPTDIR%\staging\*"
)
copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-installer.txt" + "%SCRIPTDIR%\Installer.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-Installer.exe"
)
if exist "%SCRIPTDIR%\Patch.7z" (
if NOT ["%SVZIP%"] == [""] (
"%SVZIP%" a "%SCRIPTDIR%\Patch.7z" "%SCRIPTDIR%\staging\*"
)
copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-patch.txt" + "%SCRIPTDIR%\Patch.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-Patch.exe"
)
if exist "%SCRIPTDIR%\Installer_x64.7z" (
if NOT ["%SVZIP%"] == [""] (
"%SVZIP%" a "%SCRIPTDIR%\Installer_x64.7z" "%SCRIPTDIR%\staging\*"
)
copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2_x64.sfx" + "%SCRIPTDIR%\sfx\config-installer.txt" + "%SCRIPTDIR%\Installer_x64.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-x64-Installer.exe"
)
if exist "%SCRIPTDIR%\Patch_x64.7z" (
if NOT ["%SVZIP%"] == [""] (
"%SVZIP%" a "%SCRIPTDIR%\Patch_x64.7z" "%SCRIPTDIR%\staging\*"
)
copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2_x64.sfx" + "%SCRIPTDIR%\sfx\config-patch.txt" + "%SCRIPTDIR%\Patch_x64.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-x64-Patch.exe"
)
del /f /q "%SCRIPTDIR%\staging\new-install\staging.txt"
del /f /q "%SCRIPTDIR%\staging\new-install\uninstall.exe"

View File

@ -1,48 +0,0 @@
Windows Install Builder
for SRB2
This installer is much like the 7-Zip self-extracting archive, except
this allows for scripting the post-install step.
This also allows for some light customization, including dialog messages
and program shortcuts.
The included install scripts manage the game data location depending on the
install location -- if installed in Program Files or AppData\Local, the
game data location is set to %UserProfile%\SRB2.
Program shortcuts are also added, as well as an uninstaller that
will remove the icons and also selectively uninstall the core game files.
The uninstaller gives you the option to preserve your game data and mods.
How to Use
----------
1. Zip up the install contents in 7z format.
* ALL FILES MUST BE IN THE `new-install/` ARCHIVE SUBFOLDER, OR THE
POST-INSTALL SCRIPT WILL NOT WORK!
* Make sure you are using the LZMA2 algorithm, which is 7-Zip's default.
2. Copy the 7z archive to this folder using the following names:
* Installer.7z - 32-bit full installer
* Patch.7z - 32-bit patch
* Installer_x64.7z - 64-bit full installer
* Patch_x64.7z - 64-bit patch
3. Set the text in VersionFilename.txt to the version identifier for the
installer's filename.
* e.g., v2121 for v2.1.21, from "SRB2-v2121-Installer.exe"
* Also look through sfx/config-installer.txt and sfx/config-patch.txt
and update the version strings. Templating is TODO.
4. Run BuildInstaller.bat [7z.exe install path]
* First argument is the path to 7z.exe. If this is not specified, the
script will try to look for it in C:\Program Files [(x86)]
* This script will automatically add the install scripts to each
installer.
Credit
------
OlegScherbakov/7zSFX
https://github.com/OlegScherbakov/7zSFX

View File

@ -1 +0,0 @@
v2121

Binary file not shown.

View File

@ -1,24 +0,0 @@
;!@Install@!UTF-8!
GUIFlags="8+32+64+4096"
GUIMode="1"
Title="Sonic Robo Blast 2 v2.1.21"
BeginPrompt="Sonic Robo Blast 2 v2.1.21\nFull Installer\n\nSelect a folder to install SRB2 in.\n\nIf you install in \"AppData\\Local\" or \"Program Files\", your game data will be saved to:\n%UserProfile%\\SRB2\n\nOtherwise, your game data will be in the installation folder.\n\nShortcuts will be created in your Start Menu."
ExtractPathText="Installation folder: (no exclamation points, please!)"
InstallPath="%LocalAppData%\\SRB2"
ExtractTitle="Installing..."
ExtractDialogText="Installing SRB2 v2.1.21...\n\nCheck out our modding community!\nWe make levels, characters, and much more!\n\nVisit http://www.srb2.org/mods"
Shortcut="Pu,{%%T\\srb2win.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2},{%%T\\},{%%T\\srb2win.exe},{0}"
Shortcut="Pu,{%%T\\srb2win.exe},{-win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (Windowed)},{%%T\\},{%%T\\srb2win.exe},{0}"
Shortcut="Pu,{%%T\\srb2win.exe},{-opengl},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (OpenGL)},{%%T\\},{%%T\\srb2win.exe},{0}"
Shortcut="Pu,{%%T\\srb2win.exe},{-opengl -win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (OpenGL, Windowed)},{%%T\\},{%%T\\srb2win.exe},{0}"
Shortcut="Pu,{%%T\\srb2dd.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (DirectDraw)},{%%T\\},{%%T\\srb2dd.exe},{0}"
Shortcut="Pu,{%%T\\srb2dd.exe},{-win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (DirectDraw, Windowed)},{%%T\\},{%%T\\srb2dd.exe},{0}"
Shortcut="Pu,{%%T\\uninstall.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{Uninstall SRB2},{%%T\\},{shell32.dll},{31}"
RunProgram="nowait:\"%%T\\new-install\\staging.bat\""
;!@InstallEnd@!

View File

@ -1,24 +0,0 @@
;!@Install@!UTF-8!
GUIFlags="8+32+64+4096"
GUIMode="1"
Title="Sonic Robo Blast 2 v2.1.21"
BeginPrompt="Sonic Robo Blast 2 v2.1.21\nPatch Installer\n\nYou must have at least v2.1.15 to use this patch.\n\nSelect your current SRB2 folder.\n\nShortcuts will be created in your Start Menu."
ExtractPathText="Current SRB2 folder: (no exclamation points, please!)"
InstallPath="%LocalAppData%\\SRB2"
ExtractTitle="Installing..."
ExtractDialogText="Installing SRB2 v2.1.21...\n\nCheck out our modding community!\nWe make levels, characters, and much more!\n\nVisit http://www.srb2.org/mods"
Shortcut="Pu,{%%T\\srb2win.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2},{%%T\\},{%%T\\srb2win.exe},{0}"
Shortcut="Pu,{%%T\\srb2win.exe},{-win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (Windowed)},{%%T\\},{%%T\\srb2win.exe},{0}"
Shortcut="Pu,{%%T\\srb2win.exe},{-opengl},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (OpenGL)},{%%T\\},{%%T\\srb2win.exe},{0}"
Shortcut="Pu,{%%T\\srb2win.exe},{-opengl -win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (OpenGL, Windowed)},{%%T\\},{%%T\\srb2win.exe},{0}"
Shortcut="Pu,{%%T\\srb2dd.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (DirectDraw)},{%%T\\},{%%T\\srb2dd.exe},{0}"
Shortcut="Pu,{%%T\\srb2dd.exe},{-win},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{SRB2 (DirectDraw, Windowed)},{%%T\\},{%%T\\srb2dd.exe},{0}"
Shortcut="Pu,{%%T\\uninstall.exe},{},{Sonic Robo Blast 2},{Sonic Robo Blast 2 (SRB2), a 3D Sonic the Hedgehog fangame.},{Uninstall SRB2},{%%T\\},{shell32.dll},{31}"
RunProgram="nowait:\"%%T\\new-install\\staging.bat\""
;!@InstallEnd@!

View File

@ -1,13 +0,0 @@
;!@Install@!UTF-8!
GUIFlags="1+2+8"
GUIMode="2"
Title="Uninstall SRB2"
BeginPrompt="Are you sure you want to uninstall Sonic Robo Blast 2?\n\nYour game data and mods will be preserved, as well as\nany extra files in your install folder."
InstallPath="%%S"
RunProgram="nowait:\"%%S\\uninstall.bat\" /y"
;!@InstallEnd@!

View File

@ -1,11 +0,0 @@
SRB2 Install Instructions
1. Move every file from the "new-install" folder to this main install folder.
2. DELETE "staging.bat" and "staging.txt"! These can mess up your installation if run by accident!
3. Optionally, create a folder in your user profile named "SRB2". This is where your game data and addons may live. For example,
C:\Users\[User]\SRB2
4. Run the game! Double-click srb2win.exe -- or see if you have Start Menu icons under "Sonic Robo Blast 2".

View File

@ -1,15 +0,0 @@
exchndl.dll
fmodex.dll
libFLAC-8.dll
libgme.dll
libintl-8.dll
libmikmod-2.dll
libogg-0.dll
libvorbis-0.dll
libvorbisfile-3.dll
r_opengl.dll
SDL2.dll
SDL2_mixer.dll
smpeg2.dll
srb2dd.exe
srb2win.exe

View File

@ -1,363 +0,0 @@
@echo off
setlocal enabledelayedexpansion
cls
:: SRB2 Install Staging
::
:: This accomplishes the following tasks:
::
:: 1. Creates a user profile folder if SRB2 is installed in AppData or Program Files, and config.cfg is not already in the install folder
::
:: 2. Moves old installation files into old-install
::
:: 3. Moves new installaton files into install folder
::
:: Get Parent folder (the SRB2 install folder)
::
:: https://wiert.me/2011/08/30/batch-file-to-get-parent-directory-not-the-directory-of-the-batch-file-but-the-parent-of-that-directory/
set "STAGINGDIR=%~dp0"
:: strip trailing backslash
set "STAGINGDIR=!STAGINGDIR:~0,-1!"
:: ~dp only works for batch file parameters and loop indexes
for %%d in ("!STAGINGDIR!") do set "INSTALLDIR=%%~dpd"
set "INSTALLDIR=!INSTALLDIR:~0,-1!"
:: Find 7z
set SVZIP=
if ["%SVZIP%"] == [""] (
if exist "!ProgramFiles(x86)!\7-Zip\7z.exe" set "SVZIP=!ProgramFiles(x86)!\7-Zip\7z.exe"
if exist "!ProgramFiles!\7-Zip\7z.exe" set "SVZIP=!ProgramFiles!\7-Zip\7z.exe"
if exist "!ProgramW6432!\7-Zip\7z.exe" set "SVZIP=!ProgramW6432!\7-Zip\7z.exe"
)
:: Is it in PATH?
if ["%SVZIP%"] == [""] (
"7z.exe" --help > NUL 2> NUL
if NOT errorlevel 1 (
set "SVZIP=7z.exe"
)
)
:: FAILSAFE: Check if staging.txt exists in the directory
:: If not, exit, so we don't mess up anything by accident.
if NOT exist "!STAGINGDIR!\staging.txt" (
exit
)
: CheckPermissionsInstall
:: Write a dummy file and check for an error. If error, we need administrator rights
:: NOTE: We should never have to deal with this because the main installer should
:: already have the rights.
mkdir "!INSTALLDIR!\install-dummy"
:: TODO elevate automatically
if errorlevel 1 (
echo Finish installing SRB2 with these steps:
echo.
echo 1. Go to your SRB2 install folder
echo.
echo !INSTALLDIR!
echo.
echo 2. Copy all files from the "new-install" subfolder into the main folder
echo and DELETE staging.bat and staging.txt!!!
echo.
echo 3. Optionally, create a folder in your user profile named "SRB2".
echo This is where your game data and addons may live.
echo To create the folder, go here:
echo.
echo !USERPROFILE!
echo.
echo If anything fails, you may delete the files and try to run the installer
echo again with Administrator Rights: Right-click on the icon and click
echo "Run as administrator."
echo.
"!SystemRoot!\explorer.exe" "!INSTALLDIR!"
set /p ADMINFINAL="Press Enter key to exit. "
exit
) else (
rmdir /s /q "!INSTALLDIR!\install-dummy"
goto CheckUserDir
)
: CheckUserDir
:: Check if we need to create !userprofile!\SRB2
set "USERDIR=!INSTALLDIR!"
:: Is config.cfg in our install dir?
if exist "!INSTALLDIR!\config.cfg" goto MoveOldInstall
:: Are we in AppData?
echo.!STAGINGDIR! | findstr /C:"!LocalAppData!" 1>nul
if errorlevel 1 (
echo.
) else (
goto SetUserDir
)
: Are we in Program Files?
echo.!STAGINGDIR! | findstr /C:"!ProgramFiles!" 1>nul
if NOT errorlevel 1 (
goto SetUserDir
)
:: Are we in Program Files (x86)?
echo.!STAGINGDIR! | findstr /C:"!ProgramFiles(X86)!" 1>nul
if NOT errorlevel 1 (
goto SetUserDir
)
:: Are we 32-bit and actually in Program Files?
echo.!STAGINGDIR! | findstr /C:"!ProgramW6432!" 1>nul
if NOT errorlevel 1 (
goto SetUserDir
)
goto MoveOldInstall
: SetUserDir
: CheckPermissionsUserDir
set "USERDIR=!UserProfile!\SRB2"
:: Check for permissions and create the folder
if exist "!USERDIR!\*" (
mkdir "!USERDIR!\install-dummy"
if errorlevel 1 (
echo User profile folder exists, but we won't operate on it.
echo.
goto MoveOldInstall
) else (
rmdir /s /q "!USERDIR!\install-dummy"
)
) else (
mkdir "!USERDIR!"
if errorlevel 1 (
echo Could not create user profile folder
echo Defaulting to install dir: "!INSTALLDIR!"
echo.
set "USERDIR=!INSTALLDIR!"
goto MoveOldInstall
)
)
:: Now copy READMEs
:: echo f answers xcopy's prompt as to whether the destination is a file or a folder
echo f | xcopy /y "!STAGINGDIR!\README.txt" "!USERDIR!\README.txt"
echo f | xcopy /y "!STAGINGDIR!\LICENSE.txt" "!USERDIR!\LICENSE.txt"
echo f | xcopy /y "!STAGINGDIR!\LICENSE-3RD-PARTY.txt" "!USERDIR!\LICENSE-3RD-PARTY.txt"
echo Your game data and mods folder is: > "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo !USERDIR! >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo Your install folder is: >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo !INSTALLDIR! >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo To run SRB2, go to: >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
echo Start Menu ^> Programs ^> Sonic Robo Blast 2 >> "!USERDIR!\^! Data and Mods Go Here ^!.txt"
:: Copy path to install folder
set "SCRIPT=!TEMP!\!RANDOM!-!RANDOM!-!RANDOM!-!RANDOM!.vbs"
echo Set oWS = WScript.CreateObject("WScript.Shell") >> "!SCRIPT!"
echo sLinkFile = "!USERDIR!\^! SRB2 Install Folder ^!.lnk" >> "!SCRIPT!"
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> "!SCRIPT!"
echo oLink.TargetPath = "!INSTALLDIR!" >> "!SCRIPT!"
echo oLink.WorkingDirectory = "!INSTALLDIR!" >> "!SCRIPT!"
echo oLink.Arguments = "" >> "!SCRIPT!"
echo oLink.IconLocation = "!INSTALLDIR!\srb2win.exe,0" >> "!SCRIPT!"
echo oLink.Save >> "!SCRIPT!"
cscript /nologo "!SCRIPT!"
del "!SCRIPT!"
:: Also do it the other way around
set "SCRIPT=!TEMP!\!RANDOM!-!RANDOM!-!RANDOM!-!RANDOM!.vbs"
echo Set oWS = WScript.CreateObject("WScript.Shell") >> "!SCRIPT!"
echo sLinkFile = "!INSTALLDIR!\^! SRB2 Data Folder ^!.lnk" >> "!SCRIPT!"
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> "!SCRIPT!"
echo oLink.TargetPath = "!USERDIR!" >> "!SCRIPT!"
echo oLink.WorkingDirectory = "!USERDIR!" >> "!SCRIPT!"
echo oLink.Arguments = "" >> "!SCRIPT!"
echo oLink.IconLocation = "!INSTALLDIR!\srb2win.exe,0" >> "!SCRIPT!"
echo oLink.Save >> "!SCRIPT!"
cscript /nologo "!SCRIPT!"
del "!SCRIPT!"
: MoveOldInstall
if exist "!INSTALLDIR!\old-install\*" (
set "OLDINSTALLDIR=!INSTALLDIR!\old-install-!RANDOM!"
) else (
set "OLDINSTALLDIR=!INSTALLDIR!\old-install"
)
mkdir "!OLDINSTALLDIR!"
::
:: Move all old install files
:: We support a list of explicit files to copy to old-install
:: And later, we also loop through our staging files, look for the pre-existing copy in
:: install root, then copy that also to old-install
::
:: Extract the uninstall-list.txt and uninstall-userdir.txt files from uninstaller.exe
:: if it exists
if exist "!INSTALLDIR!\uninstall.exe" (
if NOT ["!SVZIP!"] == [""] (
"!SVZIP!" x "!INSTALLDIR!\uninstall.exe" "uninstall-list.txt" -o"!INSTALLDIR!"
"!SVZIP!" x "!INSTALLDIR!\uninstall.exe" "uninstall-userdir.txt" -o"!INSTALLDIR!"
)
)
set OLDINSTALLCHANGED=
if exist "!STAGINGDIR!\old-install-list.txt" (
goto MoveOldInstallOldFiles
) else (
goto MoveOldInstallNewFiles
)
: MoveOldInstallOldFiles
set "TESTFILE=!TEMP!\!RANDOM!.txt"
:: Do our failsafes before copying the file in the list
:: See uninstall.bat for details
for /F "usebackq tokens=*" %%A in ("!STAGINGDIR!\old-install-list.txt") do (
if exist "!INSTALLDIR!\%%A" (
if NOT ["%%A"] == [""] (
if NOT ["%%A"] == ["%~nx0"] (
echo %%A> "!TESTFILE!"
findstr /r ".*[<>:\"\"/\\|?*%%].*" "!TESTFILE!" >nul
if !errorlevel! equ 0 (
echo %%A has invalid characters, skipping...
) else (
if exist "!INSTALLDIR!\%%A\*" (
echo %%A is a folder, skipping...
) else (
echo Moving !INSTALLDIR!\%%A to "old-install" folder
echo f | xcopy /y /v "!INSTALLDIR!\%%A" "!OLDINSTALLDIR!\%%A"
if errorlevel 0 del /f /q "!INSTALLDIR!\%%A"
)
)
)
)
)
)
del /q /f "!STAGINGDIR!\old-install-list.txt"
for %%F in ("!OLDINSTALLDIR!\*") DO (
set OLDINSTALLCHANGED=1
goto MoveOldInstallNewFiles
)
: MoveOldInstallNewFiles
:: Save a list of standard files
:: So the uninstall script will know what to remove
:: Append to any existing file, in case we are a patch
dir /b /a-d "!STAGINGDIR!" >> "!INSTALLDIR!\uninstall-list.txt"
:: Overwrite the last known gamedata folder
echo !USERDIR! > "!INSTALLDIR!\uninstall-userdir.txt"
:: Add the install-generated to the uninstall list
:: NO FOLLOWING SPACES AFTER THE FILENAME!!!
echo uninstall.bat>> "!INSTALLDIR!\uninstall-list.txt"
echo uninstall-list.txt>> "!INSTALLDIR!\uninstall-list.txt"
echo uninstall-userdir.txt>> "!INSTALLDIR!\uninstall-list.txt"
:: *ahem* Prints as ^! SRB2 Data Folder ^!.lnk
:: We need to escape the exclamations (^^!) and the carets themselves (^^^^)
echo ^^^^^^! SRB2 Data Folder ^^^^^^!.lnk>> "!INSTALLDIR!\uninstall-list.txt"
:: Add the uninstall list files to the uninstall EXE
if NOT ["!SVZIP!"] == [""] (
if exist "!INSTALLDIR!\new-install\uninstall.exe" (
"!SVZIP!" a "!INSTALLDIR!\new-install\uninstall.exe" "!INSTALLDIR!\uninstall-list.txt" -sdel
"!SVZIP!" a "!INSTALLDIR!\new-install\uninstall.exe" "!INSTALLDIR!\uninstall-userdir.txt" -sdel
)
)
:: Start moving files
for %%F in ("!STAGINGDIR!\*") DO (
if exist "!INSTALLDIR!\%%~nxF" (
set OLDINSTALLCHANGED=1
move "!INSTALLDIR!\%%~nxF" "!OLDINSTALLDIR!\%%~nxF"
)
if NOT ["%%~nxF"] == ["staging.bat"] (
if NOT ["%%~nxF"] == ["staging.txt"] (
move "!STAGINGDIR!\%%~nxF" "!INSTALLDIR!\%%~nxF"
)
)
)
: Finished
del /q /f "!INSTALLDIR!\^! SRB2 INSTALL INSTRUCTIONS ^!.txt"
set MSGEXE=
if exist "!SystemRoot!\System32\msg.exe" (
set MSGEXE=!SystemRoot!\System32\msg.exe
) else (
if exist "!SystemRoot!\Sysnative\msg.exe" (
set MSGEXE=!SystemRoot!\Sysnative\msg.exe
)
)
if ["!OLDINSTALLCHANGED!"] == ["1"] (
"!systemroot!\explorer.exe" /select, "!OLDINSTALLDIR!"
echo Finished^^! Some of your old installation files were moved to the "old-install" folder. > !TEMP!\srb2msgprompt.txt
echo. >> !TEMP!\srb2msgprompt.txt
echo If you no longer need these files, you may delete the folder safely. >> !TEMP!\srb2msgprompt.txt
echo. >> !TEMP!\srb2msgprompt.txt
echo To run SRB2, go to: Start Menu ^> Programs ^> Sonic Robo Blast 2. >> !TEMP!\srb2msgprompt.txt
!MSGEXE! "!username!" < !TEMP!\srb2msgprompt.txt
del !TEMP!\srb2msgprompt.txt
) else (
if /I ["!USERDIR!"] == ["!INSTALLDIR!"] (
"!systemroot!\explorer.exe" "!INSTALLDIR!"
echo Finished^^! > !TEMP!\srb2msgprompt.txt
echo. >> !TEMP!\srb2msgprompt.txt
echo To run SRB2, go to: Start Menu ^> Programs ^> Sonic Robo Blast 2. >> !TEMP!\srb2msgprompt.txt
!MSGEXE! "!username!" < !TEMP!\srb2msgprompt.txt
del !TEMP!\srb2msgprompt.txt
) else (
"!systemroot!\explorer.exe" "!USERDIR!"
echo Finished^^! You may find your game data in this folder: > !TEMP!\srb2msgprompt.txt
echo. >> !TEMP!\srb2msgprompt.txt
echo !USERDIR! >> !TEMP!\srb2msgprompt.txt
echo. >> !TEMP!\srb2msgprompt.txt
echo To run SRB2, go to: Start Menu ^> Programs ^> Sonic Robo Blast 2. >> !TEMP!\srb2msgprompt.txt
!MSGEXE! "!username!" < !TEMP!\srb2msgprompt.txt
del !TEMP!\srb2msgprompt.txt
)
)
: Attempt to remove OLDINSTALLDIR, in case it's empty
rmdir /q "!OLDINSTALLDIR!"
cd \
start "" /b "cmd" /s /c " del /f /q "%STAGINGDIR%\*"&rmdir /s /q "%STAGINGDIR%"&exit /b "

View File

@ -1,183 +0,0 @@
@echo off
setlocal enabledelayedexpansion
cls
set "INSTALLDIR=%~dp0"
set "INSTALLDIR=!INSTALLDIR:~0,-1!"
set /p USERDIR=<"!INSTALLDIR!\uninstall-userdir.txt"
set "USERDIR=!USERDIR:~0,-1!"
: ProceedPrompt
if ["%1"] == ["/y"] (
set "PROCEED=1"
) else (
set PROCEED=
set /p PROCEED="Are you sure you want to uninstall SRB2? [yes/no] "
if /I ["!PROCEED:~0,1!"] == ["n"] exit
if /I ["!PROCEED!"] == ["y"] (
echo Type Yes or No
echo.
goto ProceedPrompt
) else (
if /I ["!PROCEED!"] == ["yes"] (
set PROCEED=1
) else (
echo.
goto ProceedPrompt
)
)
)
:: Failsafe, in case we Ctrl+C and decline "Terminate batch file?"
if NOT ["!PROCEED!"] == ["1"] (
exit
)
: CheckPermissions
:: Write a dummy file and check for an error. If error, we need administrator rights
mkdir "!INSTALLDIR!\uninstall-dummy"
:: TODO elevate automatically
if errorlevel 1 (
echo We need Administrator Rights to uninstall SRB2.
echo.
echo Try running this uninstaller by right-clicking on the icon
echo and click "Run as administrator"
echo.
set /p ADMINFINAL="Press Enter key to exit. "
exit
) else (
rmdir /s /q "!INSTALLDIR!\uninstall-dummy"
goto DeleteFiles
)
: DeleteFiles
:: Our deletion list is a list of filenames, no paths, in the current folder
::
:: We apply the following failsafes:
:: 1. Is filename the script itself?
:: 2. Does filename have illegal characters? https://stackoverflow.com/a/33625339/241046
:: 3. Is filename a directory?
::
:: TODO hack this to support .\file.txt relative paths
:: Can %%A be substring'd to get only the filename and extension?
:: If so, print that to the temp file instead of the whole line
:: And possibly do the folder check before the invalid char check.
:: ALSO: Don't honor upward relative paths! (..\)
::
set "TESTFILE=!TEMP!\!RANDOM!.txt"
for /F "usebackq tokens=*" %%A in ("!INSTALLDIR!\uninstall-list.txt") do (
if exist "!INSTALLDIR!\%%A" (
if NOT ["%%A"] == [""] (
if NOT ["%%A"] == ["%~nx0"] (
echo %%A> "!TESTFILE!"
findstr /r ".*[<>:\"\"/\\|?*%%].*" "!TESTFILE!" >nul
if !errorlevel! equ 0 (
echo %%A has invalid characters, skipping...
) else (
if exist "!INSTALLDIR!\%%A\*" (
echo %%A is a folder, skipping...
) else (
echo Deleting !INSTALLDIR!\%%A
del /q /f "!INSTALLDIR!\%%A"
)
)
)
)
)
)
del /q /f "!TESTFILE!"
: AllDone
:: Delete the program icons
echo Deleting your program icons...
echo.
cd \
rmdir /s /q "!AppData!\Microsoft\Windows\Start Menu\Programs\Sonic Robo Blast 2"
:: Check if our install folder is non-empty
set USERDIRFILLED=
set INSTALLDIRFILLED=
for /F %%i in ('dir /b /a "!USERDIR!\*"') do (
if NOT ["%%i"] == ["%~nx0"] (
set USERDIRFILLED=1
goto InstallFilledCheck
)
)
: InstallFilledCheck
if /I NOT ["!USERDIR!"] == ["!INSTALLDIR!"] (
for /F %%i in ('dir /b /a "!INSTALLDIR!\*"') do (
if ["%%i"] == ["%~nx0"] (
echo.
) else (
set INSTALLDIRFILLED=1
goto Final
)
)
)
: Final
echo All done^^! Visit http://www.srb2.org if you want to play SRB2 again^^!
echo.
set "FINALPROMPT=Press Enter key to exit."
if ["!USERDIRFILLED!"] == ["1"] (
echo We left your game data and mods alone, so you may delete those manually.
echo.
echo !USERDIR!
echo.
set "FINALPROMPT=Do you want to view your data? [yes/no]"
)
if ["!INSTALLDIRFILLED!"] == ["1"] (
echo We left some extra files alone in your install folder.
echo.
echo !INSTALLDIR!
echo.
set "FINALPROMPT=Do you want to view your data? [yes/no]"
)
set FINALRESPONSE=
set /p FINALRESPONSE="!FINALPROMPT! "
if NOT ["!FINALPROMPT!"] == ["Press Enter key to exit."] (
if /I ["!FINALRESPONSE:~0,1!"] == ["y"] (
if ["!USERDIRFILLED!"] == ["1"] (
"!SystemRoot!\explorer.exe" "!USERDIR!"
)
if ["!INSTALLDIRFILLED!"] == ["1"] (
"!SystemRoot!\explorer.exe" "!INSTALLDIR!"
)
) else (
if ["!FINALRESPONSE!"] == [""] (
if ["!USERDIRFILLED!"] == ["1"] (
"!SystemRoot!\explorer.exe" "!USERDIR!"
)
if ["!INSTALLDIRFILLED!"] == ["1"] (
"!SystemRoot!\explorer.exe" "!INSTALLDIR!"
)
)
)
)
: DeferredDelete
:: Now let's delete our installation folder!
cd \
start "" /b "cmd" /s /c " del /q /f "%INSTALLDIR%\uninstall.bat"&timeout /t 2 > NUL&rmdir "%INSTALLDIR%"&exit /b "