Merge branch SRB2:next into tsourdt3rdport3

This commit is contained in:
Alam Ed Arias 2025-01-10 03:51:04 +00:00
commit e355cf832e
181 changed files with 5051 additions and 3320 deletions

View file

@ -61,7 +61,7 @@
- - | - - |
# apt_update # apt_update
echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing" echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing"
- apt-get update - timeout 2m apt-get update || timeout 2m apt-get update
- | - |
# apt_update # apt_update
echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K" echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K"

View file

@ -39,7 +39,7 @@ https://facebook.com/SonicRoboBlast2
COPYRIGHT AND DISCLAIMER COPYRIGHT AND DISCLAIMER
Design and content in Sonic Robo Blast 2 is copyright 1998-2023 by Sonic Team Jr. Design and content in Sonic Robo Blast 2 is copyright 1998-2024 by Sonic Team Jr.
All original material in this game is copyrighted by their respective owners, and no copyright infringement is intended. Sonic Team Jr. is in no way affiliated with SEGA or Sonic Team, and we do not claim ownership of any of SEGA's intellectual property used in SRB2. All original material in this game is copyrighted by their respective owners, and no copyright infringement is intended. Sonic Team Jr. is in no way affiliated with SEGA or Sonic Team, and we do not claim ownership of any of SEGA's intellectual property used in SRB2.

View file

@ -12,7 +12,7 @@ Upstream Author(s):
Copyright: Copyright:
Copyright (C) 1998-2018 by Sonic Team Junior Copyright (C) 1998-2024 by Sonic Team Junior
License: License:
@ -21,7 +21,7 @@ License:
The Debian packaging is: The Debian packaging is:
Copyright (C) 2010 Callum Dickinson <gcfreak_ag20@hotmail.com> Copyright (C) 2010 Callum Dickinson <gcfreak_ag20@hotmail.com>
Copyright (C) 2010-2018 by Sonic Team Junior <stjr@srb2.org> Copyright (C) 2010-2024 by Sonic Team Junior <stjr@srb2.org>
and is licensed under the GPL version 2, and is licensed under the GPL version 2,
see "/usr/share/common-licenses/GPL-2". see "/usr/share/common-licenses/GPL-2".

View file

@ -12,7 +12,7 @@ Upstream Author(s):
Copyright: Copyright:
Copyright (C) 1998-2018 by Sonic Team Junior Copyright (C) 1998-2024 by Sonic Team Junior
License: License:
@ -21,7 +21,7 @@ License:
The Debian packaging is: The Debian packaging is:
Copyright (C) 2010 Callum Dickinson <gcfreak_ag20@hotmail.com> Copyright (C) 2010 Callum Dickinson <gcfreak_ag20@hotmail.com>
Copyright (C) 2010-2018 by Sonic Team Junior <stjr@srb2.org> Copyright (C) 2010-2024 by Sonic Team Junior <stjr@srb2.org>
and is licensed under the GPL version 2, and is licensed under the GPL version 2,
see "/usr/share/common-licenses/GPL-2". see "/usr/share/common-licenses/GPL-2".

View file

@ -1,5 +1,5 @@
=============================================================================== ===============================================================================
Universal Doom Map Format Sonic Robo Blast 2 extensions v1.0 19.02.2024 Universal Doom Map Format Sonic Robo Blast 2 extensions v1.0 19.06.2024
Copyright (c) 2024 Sonic Team Junior Copyright (c) 2024 Sonic Team Junior
uses Universal Doom Map Format Specification v1.1 as a template, uses Universal Doom Map Format Specification v1.1 as a template,
@ -143,6 +143,9 @@ Sonic Robo Blast 2 defines the following standardized fields:
offsetx_bottom = <float>; // X offset for lower texture. Default = 0.0. offsetx_bottom = <float>; // X offset for lower texture. Default = 0.0.
offsety_bottom = <float>; // Y offset for lower texture. Default = 0.0. offsety_bottom = <float>; // Y offset for lower texture. Default = 0.0.
light = <integer>; // Light level, relative to 'sector' light level. Default = 0.
lightabsolute = <bool>; // true = 'light' is an absolute value, ignoring 'sector' light level.
comment = <string>; // A comment. Implementors should attach no special comment = <string>; // A comment. Implementors should attach no special
// semantic meaning to this field. // semantic meaning to this field.
} }

View file

@ -115,7 +115,7 @@ mapformat_udmf
// Enables setting distinct brightness for floor, ceiling, and walls // Enables setting distinct brightness for floor, ceiling, and walls
distinctfloorandceilingbrightness = true; distinctfloorandceilingbrightness = true;
distinctwallbrightness = false; distinctwallbrightness = true;
// Enables setting distinct brightness for upper, middle, and lower sidedef parts // Enables setting distinct brightness for upper, middle, and lower sidedef parts
distinctsidedefpartbrightness = false; distinctsidedefpartbrightness = false;

View file

@ -280,18 +280,18 @@ universalfields
default = ""; default = "";
} }
//light light
//{ {
// type = 0; type = 0;
// default = 0; default = 0;
//} }
//
//lightabsolute lightabsolute
//{ {
// type = 3; type = 3;
// default = false; default = false;
//} }
//
//light_top //light_top
//{ //{
// type = 0; // type = 0;

View file

@ -172,6 +172,11 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
endif() endif()
endif() endif()
if("${CMAKE_SYSTEM_NAME}" MATCHES "Haiku")
target_compile_definitions(SRB2SDL2 PRIVATE -DNOEXECINFO)
target_link_libraries(SRB2SDL2 PRIVATE network)
endif()
if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
target_compile_definitions(SRB2SDL2 PRIVATE -DMACOSX) target_compile_definitions(SRB2SDL2 PRIVATE -DMACOSX)
endif() endif()

View file

@ -4,7 +4,6 @@
# Previously featured:\ # Previously featured:\
PANDORA\ PANDORA\
HAIKU\
DUMMY\ DUMMY\
DJGPPDOS\ DJGPPDOS\
SOLARIS\ SOLARIS\
@ -17,6 +16,7 @@ all_systems:=\
UNIX\ UNIX\
LINUX\ LINUX\
FREEBSD\ FREEBSD\
HAIKU\
# check for user specified system # check for user specified system
ifeq (,$(filter $(all_systems),$(.VARIABLES))) ifeq (,$(filter $(all_systems),$(.VARIABLES)))
@ -35,6 +35,8 @@ system:=$(shell uname -s)
ifeq ($(system),Linux) ifeq ($(system),Linux)
new_system:=LINUX new_system:=LINUX
else ifeq ($(system),Haiku)
new_system:=HAIKU
else else
$(error \ $(error \

71
src/Makefile.d/haiku.mk Normal file
View file

@ -0,0 +1,71 @@
#
# Makefile options for Haiku
#
opts+=-DUNIXCOMMON -DLUA_USE_POSIX
ifndef DEDICATED
ifndef DUMMY
SDL?=1
DEDICATED?=0
endif
endif
NOEXECINFO=1
ifeq (${SDL},1)
EXENAME?=srb2haiku
else ifeq (${DEDICATED},1)
EXENAME?=srb2haikud
endif
ifndef NONET
libs+=-lnetwork
endif
define _set =
$(1)_CFLAGS?=$($(1)_opts)
$(1)_LDFLAGS?=$($(1)_libs)
endef
lib:=../libs/gme
LIBGME_opts:=-I$(lib)/include
LIBGME_libs:=-l:libgme.so.0
$(eval $(call _set,LIBGME))
lib:=../libs/libopenmpt
LIBOPENMPT_opts:=-I$(lib)/inc
LIBOPENMPT_libs:=-l:libopenmpt.so.0
$(eval $(call _set,LIBOPENMPT))
ifdef SDL
lib:=../libs/SDL2_mixer
mixer_opts:=-I$(lib)/include
mixer_libs:=-l:libSDL2_mixer-2.0.so.0
lib:=../libs/SDL2
SDL_opts:=-I$(lib)/include $(mixer_opts)
SDL_libs:=$(mixer_libs) -l:libSDL2-2.0.so.0
$(eval $(call _set,SDL))
endif
lib:=../libs/zlib
ZLIB_opts:=-I$(lib)
ZLIB_libs:=-l:libz.so.1
$(eval $(call _set,ZLIB))
ifndef PNG_CONFIG
PNG_opts:=
PNG_libs:=-l:libpng16.so.16
$(eval $(call _set,PNG))
endif
lib:=../libs/curl
CURL_opts:=-I$(lib)/include
CURL_libs:=-l:libcurl.so.4
$(eval $(call _set,CURL))
lib:=../libs/miniupnpc
MINIUPNPC_opts:=-I$(lib)/include
MINIUPNPC_libs:=-l:libminiupnpc.so.17
$(eval $(call _set,MINIUPNPC))

View file

@ -35,6 +35,10 @@ endif
else ifdef FREEBSD else ifdef FREEBSD
UNIX=1 UNIX=1
platform=freebsd platform=freebsd
else ifdef HAIKU
# Give Haiku its own configuration, since it
# isn't actually UNIX.
include Makefile.d/haiku.mk
else ifdef SOLARIS # FIXME: UNTESTED else ifdef SOLARIS # FIXME: UNTESTED
UNIX=1 UNIX=1
platform=solaris platform=solaris

View file

@ -33,11 +33,13 @@ else
opts+=-DHAVE_MIXER opts+=-DHAVE_MIXER
sources+=sdl/mixer_sound.c sources+=sdl/mixer_sound.c
ifdef HAVE_MIXERX ifndef HAIKU # Haiku has a special import path
opts+=-DHAVE_MIXERX ifdef HAVE_MIXERX
libs+=-lSDL2_mixer_ext opts+=-DHAVE_MIXERX
else libs+=-lSDL2_mixer_ext
libs+=-lSDL2_mixer else
libs+=-lSDL2_mixer
endif
endif endif
endif endif

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2007-2016 by John "JTE" Muniz. // Copyright (C) 2007-2016 by John "JTE" Muniz.
// Copyright (C) 2011-2023 by Sonic Team Junior. // Copyright (C) 2011-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -1722,8 +1722,7 @@ badinput:
static boolean serverloading = false; static boolean serverloading = false;
static consvar_t * static consvar_t *ReadNetVar(save_t *p, char **return_value, boolean *return_stealth)
ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth)
{ {
UINT16 netid; UINT16 netid;
char *val; char *val;
@ -1731,10 +1730,10 @@ ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth)
consvar_t *cvar; consvar_t *cvar;
netid = READUINT16 (*p); netid = P_ReadUINT16(p);
val = (char *)*p; val = (char *)&p->buf[p->pos];
SKIPSTRING (*p); P_SkipString(p);
stealth = READUINT8 (*p); stealth = P_ReadUINT8(p);
cvar = CV_FindNetVar(netid); cvar = CV_FindNetVar(netid);
@ -1752,8 +1751,7 @@ ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth)
} }
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
static consvar_t * static consvar_t *ReadOldDemoVar(save_t *p, char **return_value, boolean *return_stealth)
ReadOldDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
{ {
UINT16 id; UINT16 id;
char *val; char *val;
@ -1761,10 +1759,10 @@ ReadOldDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
old_demo_var_t *demovar; old_demo_var_t *demovar;
id = READUINT16 (*p); id = P_ReadUINT16(p);
val = (char *)*p; val = (char *)&p->buf[p->pos];
SKIPSTRING (*p); P_SkipString(p);
stealth = READUINT8 (*p); stealth = P_ReadUINT8(p);
demovar = CV_FindOldDemoVar(id); demovar = CV_FindOldDemoVar(id);
@ -1783,8 +1781,7 @@ ReadOldDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
} }
#endif/*OLD22DEMOCOMPAT*/ #endif/*OLD22DEMOCOMPAT*/
static consvar_t * static consvar_t *ReadDemoVar(save_t *p, char **return_value, boolean *return_stealth)
ReadDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
{ {
char *name; char *name;
char *val; char *val;
@ -1792,11 +1789,11 @@ ReadDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
consvar_t *cvar; consvar_t *cvar;
name = (char *)*p; name = (char *)&p->buf[p->pos];
SKIPSTRING (*p); P_SkipString(p);
val = (char *)*p; val = (char *)&p->buf[p->pos];
SKIPSTRING (*p); P_SkipString(p);
stealth = READUINT8 (*p); stealth = P_ReadUINT8(p);
cvar = CV_FindVar(name); cvar = CV_FindVar(name);
@ -1826,41 +1823,46 @@ static void Got_NetVar(UINT8 **p, INT32 playernum)
return; return;
} }
cvar = ReadNetVar(p, &svalue, &stealth); save_t save_p;
save_p.buf = *p;
save_p.size = MAXTEXTCMD;
save_p.pos = 0;
cvar = ReadNetVar(&save_p, &svalue, &stealth);
*p = &save_p.buf[save_p.pos];
if (cvar) if (cvar)
Setvalue(cvar, svalue, stealth); Setvalue(cvar, svalue, stealth);
} }
void CV_SaveVars(UINT8 **p, boolean in_demo) void CV_SaveVars(save_t *p, boolean in_demo)
{ {
consvar_t *cvar; consvar_t *cvar;
UINT8 *count_p = *p; UINT8 *count_p = &p->buf[p->pos];
UINT16 count = 0; UINT16 count = 0;
// send only changed cvars ... // send only changed cvars ...
// the client will reset all netvars to default before loading // the client will reset all netvars to default before loading
WRITEUINT16(*p, 0x0000); P_WriteUINT16(p, 0x0000);
for (cvar = consvar_vars; cvar; cvar = cvar->next) for (cvar = consvar_vars; cvar; cvar = cvar->next)
if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar))
{ {
if (in_demo) if (in_demo)
{ {
WRITESTRING(*p, cvar->name); P_WriteString(p, cvar->name);
} }
else else
{ {
WRITEUINT16(*p, cvar->netid); P_WriteUINT16(p, cvar->netid);
} }
WRITESTRING(*p, cvar->string); P_WriteString(p, cvar->string);
WRITEUINT8(*p, false); P_WriteUINT8(p, false);
++count; ++count;
} }
WRITEUINT16(count_p, count); WRITEUINT16(count_p, count);
} }
static void CV_LoadVars(UINT8 **p, static void CV_LoadVars(save_t *p,
consvar_t *(*got)(UINT8 **p, char **ret_value, boolean *ret_stealth)) consvar_t *(*got)(save_t *p, char **ret_value, boolean *ret_stealth))
{ {
const boolean store = (client || demoplayback); const boolean store = (client || demoplayback);
@ -1888,7 +1890,7 @@ static void CV_LoadVars(UINT8 **p,
} }
} }
count = READUINT16(*p); count = P_ReadUINT16(p);
while (count--) while (count--)
{ {
cvar = (*got)(p, &val, &stealth); cvar = (*got)(p, &val, &stealth);
@ -1921,19 +1923,19 @@ void CV_RevertNetVars(void)
} }
} }
void CV_LoadNetVars(UINT8 **p) void CV_LoadNetVars(save_t *p)
{ {
CV_LoadVars(p, ReadNetVar); CV_LoadVars(p, ReadNetVar);
} }
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
void CV_LoadOldDemoVars(UINT8 **p) void CV_LoadOldDemoVars(save_t *p)
{ {
CV_LoadVars(p, ReadOldDemoVar); CV_LoadVars(p, ReadOldDemoVar);
} }
#endif #endif
void CV_LoadDemoVars(UINT8 **p) void CV_LoadDemoVars(save_t *p)
{ {
CV_LoadVars(p, ReadDemoVar); CV_LoadVars(p, ReadDemoVar);
} }
@ -1986,7 +1988,7 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth)
if (!var->string) if (!var->string)
I_Error("CV_Set: %s no string set!\n", var->name); I_Error("CV_Set: %s no string set!\n", var->name);
#endif #endif
if (!var || !var->string || !value || !stricmp(var->string, value)) if (!var || !var->string || !value || (var->can_change == NULL && !stricmp(var->string, value)))
return; // no changes return; // no changes
if (var->flags & CV_NETVAR) if (var->flags & CV_NETVAR)

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -15,6 +15,7 @@
#include <stdio.h> #include <stdio.h>
#include "doomdef.h" #include "doomdef.h"
#include "p_saveg.h"
//=================================== //===================================
// Command buffer & command execution // Command buffer & command execution
@ -218,19 +219,19 @@ void CV_AddValue(consvar_t *var, INT32 increment);
void CV_SaveVariables(FILE *f); void CV_SaveVariables(FILE *f);
// load/save gamesate (load and save option and for network join in game) // load/save gamesate (load and save option and for network join in game)
void CV_SaveVars(UINT8 **p, boolean in_demo); void CV_SaveVars(save_t *p, boolean in_demo);
#define CV_SaveNetVars(p) CV_SaveVars(p, false) #define CV_SaveNetVars(p) CV_SaveVars(p, false)
void CV_LoadNetVars(UINT8 **p); void CV_LoadNetVars(save_t *p);
// then revert after leaving a netgame // then revert after leaving a netgame
void CV_RevertNetVars(void); void CV_RevertNetVars(void);
#define CV_SaveDemoVars(p) CV_SaveVars(p, true) #define CV_SaveDemoVars(p) CV_SaveVars(p, true)
void CV_LoadDemoVars(UINT8 **p); void CV_LoadDemoVars(save_t *p);
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
void CV_LoadOldDemoVars(UINT8 **p); void CV_LoadOldDemoVars(save_t *p);
#endif #endif
// reset cheat netvars after cheats is deactivated // reset cheat netvars after cheats is deactivated

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -679,13 +679,13 @@ static void D_Display(void)
s[sizeof s - 1] = '\0'; s[sizeof s - 1] = '\0';
snprintf(s, sizeof s - 1, "get %d b/s", getbps); snprintf(s, sizeof s - 1, "get %d b/s", getbps);
V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-40, V_YELLOWMAP, s); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-40, V_YELLOWMAP, s);
snprintf(s, sizeof s - 1, "send %d b/s", sendbps); snprintf(s, sizeof s - 1, "send %d b/s", sendbps);
V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-30, V_YELLOWMAP, s); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-30, V_YELLOWMAP, s);
snprintf(s, sizeof s - 1, "GameMiss %.2f%%", gamelostpercent); snprintf(s, sizeof s - 1, "GameMiss %.2f%%", gamelostpercent);
V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-20, V_YELLOWMAP, s); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-20, V_YELLOWMAP, s);
snprintf(s, sizeof s - 1, "SysMiss %.2f%%", lostpercent); snprintf(s, sizeof s - 1, "SysMiss %.2f%%", lostpercent);
V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-10, V_YELLOWMAP, s); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-10, V_YELLOWMAP, s);
} }
if (cv_perfstats.value) if (cv_perfstats.value)
@ -1250,7 +1250,7 @@ void D_SRB2Main(void)
// Print GPL notice for our console users (Linux) // Print GPL notice for our console users (Linux)
CONS_Printf( CONS_Printf(
"\n\nSonic Robo Blast 2\n" "\n\nSonic Robo Blast 2\n"
"Copyright (C) 1998-2023 by Sonic Team Junior\n\n" "Copyright (C) 1998-2024 by Sonic Team Junior\n\n"
"This program comes with ABSOLUTELY NO WARRANTY.\n\n" "This program comes with ABSOLUTELY NO WARRANTY.\n\n"
"This is free software, and you are welcome to redistribute it\n" "This is free software, and you are welcome to redistribute it\n"
"and/or modify it under the terms of the GNU General Public License\n" "and/or modify it under the terms of the GNU General Public License\n"
@ -1535,7 +1535,7 @@ void D_SRB2Main(void)
I_Error("Cannot find a map remotely named '%s'\n", word); I_Error("Cannot find a map remotely named '%s'\n", word);
else else
{ {
if (!M_CheckParm("-server")) if (!(M_CheckParm("-server") || dedicated))
G_SetUsedCheats(true); G_SetUsedCheats(true);
autostart = true; autostart = true;
} }

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -51,6 +51,8 @@ typedef struct thinker_s
// killough 11/98: count of how many other objects reference // killough 11/98: count of how many other objects reference
// this one using pointers. Used for garbage collection. // this one using pointers. Used for garbage collection.
INT32 references; INT32 references;
boolean removing;
boolean cachable; boolean cachable;
#ifdef PARANOIA #ifdef PARANOIA

View file

@ -3,7 +3,7 @@
// //
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Portions Copyright (C) 1998-2000 by DooM Legacy Team. // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2014-2023 by Sonic Team Junior. // Copyright (C) 2014-2024 by Sonic Team Junior.
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -705,10 +705,9 @@ typedef struct
static feild_t tty_con; static feild_t tty_con;
// when printing general stuff to stdout stderr (Sys_Printf) // lock to prevent clearing partial lines, since not everything
// we need to disable the tty console stuff // printed ends on a newline.
// this increments so we can recursively disable static boolean ttycon_ateol = true;
static INT32 ttycon_hide = 0;
// some key codes that the terminal may be using // some key codes that the terminal may be using
// TTimo NOTE: I'm not sure how relevant this is // TTimo NOTE: I'm not sure how relevant this is
static INT32 tty_erase; static INT32 tty_erase;
@ -736,63 +735,31 @@ static inline void tty_FlushIn(void)
// TTimo NOTE: it seems on some terminals just sending '\b' is not enough // TTimo NOTE: it seems on some terminals just sending '\b' is not enough
// so for now, in any case we send "\b \b" .. yeah well .. // so for now, in any case we send "\b \b" .. yeah well ..
// (there may be a way to find out if '\b' alone would work though) // (there may be a way to find out if '\b' alone would work though)
// Hanicef NOTE: using \b this way is unreliable because of terminal state,
// it's better to use \r to reset the cursor to the beginning of the
// line and clear from there.
static void tty_Back(void) static void tty_Back(void)
{ {
char key; write(STDOUT_FILENO, "\r", 1);
ssize_t d; if (tty_con.cursor>0)
key = '\b'; {
d = write(STDOUT_FILENO, &key, 1); write(STDOUT_FILENO, tty_con.buffer, tty_con.cursor);
key = ' '; }
d = write(STDOUT_FILENO, &key, 1); write(STDOUT_FILENO, " \b", 2);
key = '\b';
d = write(STDOUT_FILENO, &key, 1);
(void)d;
} }
static void tty_Clear(void) static void tty_Clear(void)
{ {
size_t i; size_t i;
write(STDOUT_FILENO, "\r", 1);
if (tty_con.cursor>0) if (tty_con.cursor>0)
{ {
for (i=0; i<tty_con.cursor; i++) for (i=0; i<tty_con.cursor; i++)
{ {
tty_Back(); write(STDOUT_FILENO, " ", 1);
} }
write(STDOUT_FILENO, "\r", 1);
} }
}
// clear the display of the line currently edited
// bring cursor back to beginning of line
static inline void tty_Hide(void)
{
//I_Assert(consolevent);
if (ttycon_hide)
{
ttycon_hide++;
return;
}
tty_Clear();
ttycon_hide++;
}
// show the current line
// FIXME TTimo need to position the cursor if needed??
static inline void tty_Show(void)
{
size_t i;
ssize_t d;
//I_Assert(consolevent);
I_Assert(ttycon_hide>0);
ttycon_hide--;
if (ttycon_hide == 0 && tty_con.cursor)
{
for (i=0; i<tty_con.cursor; i++)
{
d = write(STDOUT_FILENO, tty_con.buffer+i, 1);
}
}
(void)d;
} }
// never exit without calling this, or your terminal will be left in a pretty bad state // never exit without calling this, or your terminal will be left in a pretty bad state
@ -900,6 +867,11 @@ static void I_GetConsoleEvents(void)
tty_con.cursor = 0; tty_con.cursor = 0;
ev.key = KEY_ENTER; ev.key = KEY_ENTER;
} }
else if (key == 0x4) // ^D, aka EOF
{
// shut down, most unix programs behave this way
I_Quit();
}
else continue; else continue;
} }
else if (tty_con.cursor < sizeof(tty_con.buffer)) else if (tty_con.cursor < sizeof(tty_con.buffer))
@ -999,20 +971,8 @@ static void I_GetConsoleEvents(void)
static void I_StartupConsole(void) static void I_StartupConsole(void)
{ {
HANDLE ci, co; HANDLE ci, co;
const INT32 ded = M_CheckParm("-dedicated"); BOOL gotConsole = AllocConsole();
BOOL gotConsole = FALSE; consolevent = !M_CheckParm("-noconsole");
if (M_CheckParm("-console") || ded)
gotConsole = AllocConsole();
#ifdef _DEBUG
else if (M_CheckParm("-noconsole") && !ded)
#else
else if (!M_CheckParm("-console") && !ded)
#endif
{
FreeConsole();
gotConsole = FALSE;
}
if (gotConsole) if (gotConsole)
{ {
SetConsoleTitleA("SRB2 Console"); SetConsoleTitleA("SRB2 Console");
@ -1040,12 +1000,7 @@ static inline void I_ShutdownConsole(void){}
static void I_GetConsoleEvents(void){} static void I_GetConsoleEvents(void){}
static inline void I_StartupConsole(void) static inline void I_StartupConsole(void)
{ {
#ifdef _DEBUG
consolevent = !M_CheckParm("-noconsole"); consolevent = !M_CheckParm("-noconsole");
#else
consolevent = M_CheckParm("-console");
#endif
framebuffer = M_CheckParm("-framebuffer"); framebuffer = M_CheckParm("-framebuffer");
if (framebuffer) if (framebuffer)
@ -1063,6 +1018,9 @@ void I_OutputMsg(const char *fmt, ...)
va_start(argptr,fmt); va_start(argptr,fmt);
len = vsnprintf(NULL, 0, fmt, argptr); len = vsnprintf(NULL, 0, fmt, argptr);
va_end(argptr); va_end(argptr);
if (len == 0)
return;
txt = malloc(len+1); txt = malloc(len+1);
va_start(argptr,fmt); va_start(argptr,fmt);
vsprintf(txt, fmt, argptr); vsprintf(txt, fmt, argptr);
@ -1152,18 +1110,20 @@ void I_OutputMsg(const char *fmt, ...)
} }
#else #else
#ifdef HAVE_TERMIOS #ifdef HAVE_TERMIOS
if (consolevent) if (consolevent && ttycon_ateol)
{ {
tty_Hide(); tty_Clear();
ttycon_ateol = false;
} }
#endif #endif
if (!framebuffer) if (!framebuffer)
fprintf(stderr, "%s", txt); fprintf(stderr, "%s", txt);
#ifdef HAVE_TERMIOS #ifdef HAVE_TERMIOS
if (consolevent) if (consolevent && txt[len-1] == '\n')
{ {
tty_Show(); write(STDOUT_FILENO, tty_con.buffer, tty_con.cursor);
ttycon_ateol = true;
} }
#endif #endif
@ -1390,8 +1350,8 @@ static const char *searchWad(const char *searchDir)
#define CHECKWADPATH(ret) \ #define CHECKWADPATH(ret) \
do { \ do { \
I_OutputMsg(",%s", returnWadPath); \ I_OutputMsg(",%s", ret); \
if (isWadPathOk(returnWadPath)) \ if (isWadPathOk(ret)) \
return ret; \ return ret; \
} while (0) } while (0)
@ -1416,7 +1376,9 @@ static const char *locateWad(void)
#ifndef NOCWD #ifndef NOCWD
// examine current dir // examine current dir
strcpy(returnWadPath, "."); strcpy(returnWadPath, ".");
CHECKWADPATH(NULL); I_OutputMsg(",%s", returnWadPath);
if (isWadPathOk(returnWadPath))
return NULL;
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
@ -1433,13 +1395,13 @@ static const char *locateWad(void)
#ifndef NOHOME #ifndef NOHOME
// find in $HOME // find in $HOME
I_OutputMsg(",HOME/" DEFAULTDIR);
if ((envstr = I_GetEnv("HOME")) != NULL) if ((envstr = I_GetEnv("HOME")) != NULL)
{ {
char *tmp = malloc(strlen(envstr) + sizeof(DEFAULTDIR)); char *tmp = malloc(strlen(envstr) + 1 + sizeof(DEFAULTDIR));
strcpy(tmp, envstr); strcpy(tmp, envstr);
strcat(tmp, "/");
strcat(tmp, DEFAULTDIR); strcat(tmp, DEFAULTDIR);
SEARCHWAD(envstr); CHECKWADPATH(tmp);
free(tmp); free(tmp);
} }
#endif #endif
@ -1468,8 +1430,10 @@ const char *I_LocateWad(void)
{ {
// change to the directory where we found srb2.pk3 // change to the directory where we found srb2.pk3
#if defined (_WIN32) #if defined (_WIN32)
waddir = _fullpath(NULL, waddir, MAX_PATH);
SetCurrentDirectoryA(waddir); SetCurrentDirectoryA(waddir);
#else #else
waddir = realpath(waddir, NULL);
if (chdir(waddir) == -1) if (chdir(waddir) == -1)
I_OutputMsg("Couldn't change working directory\n"); I_OutputMsg("Couldn't change working directory\n");
#endif #endif

View file

@ -157,7 +157,7 @@ void I_wake_all_cond(I_cond *anchor)
pthread_mutex_lock(&thread_lock); pthread_mutex_lock(&thread_lock);
if (*anchor == NULL) if (*anchor == NULL)
{ {
*anchor = malloc(sizeof(pthread_t)); *anchor = malloc(sizeof(pthread_cond_t));
pthread_cond_init(*anchor, NULL); pthread_cond_init(*anchor, NULL);
} }
pthread_mutex_unlock(&thread_lock); pthread_mutex_unlock(&thread_lock);

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -28,6 +28,12 @@ static inline int lib_freeslot(lua_State *L)
if (!lua_lumploading) if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
if (!deh_loaded)
{
initfreeslots();
deh_loaded = true;
}
while (n-- > 0) while (n-- > 0)
{ {
s = Z_StrDup(luaL_checkstring(L,1)); s = Z_StrDup(luaL_checkstring(L,1));

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -4483,6 +4483,8 @@ const char *const PLAYERFLAG_LIST[] = {
"CANCARRY", // Can carry? "CANCARRY", // Can carry?
"FINISHED", "FINISHED",
"SHIELDDOWN", // Shield has been pressed.
NULL // stop loop here. NULL // stop loop here.
}; };

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -192,7 +192,10 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
INT32 i; INT32 i;
if (!deh_loaded) if (!deh_loaded)
{
initfreeslots(); initfreeslots();
deh_loaded = true;
}
deh_num_warning = 0; deh_num_warning = 0;
@ -605,14 +608,10 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
if (deh_num_warning) if (deh_num_warning)
{ {
CONS_Printf(M_GetText("%d warning%s in the SOC lump\n"), deh_num_warning, deh_num_warning == 1 ? "" : "s"); CONS_Printf(M_GetText("%d warning%s in the SOC lump\n"), deh_num_warning, deh_num_warning == 1 ? "" : "s");
if (devparm) { if (devparm)
I_Error("%s%s",va(M_GetText("%d warning%s in the SOC lump\n"), deh_num_warning, deh_num_warning == 1 ? "" : "s"), M_GetText("See log.txt for details.\n")); I_Error("%s%s",va(M_GetText("%d warning%s in the SOC lump\n"), deh_num_warning, deh_num_warning == 1 ? "" : "s"), M_GetText("See log.txt for details.\n"));
//while (!I_GetKey())
//I_OsPolling();
}
} }
deh_loaded = true;
Z_Free(s); Z_Free(s);
} }

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -1065,12 +1065,12 @@ static const char *credits[] = {
"Julio \"Chaos Zero 64\" Guir", "Julio \"Chaos Zero 64\" Guir",
"\"Hanicef\"", "\"Hanicef\"",
"\"Hannu_Hanhi\"", // For many OpenGL performance improvements! "\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
"\"hazepastel\"",
"Kepa \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"Thomas \"Shadow Hog\" Igoe", "Thomas \"Shadow Hog\" Igoe",
"Iestyn \"Monster Iestyn\" Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"\"Kaito Sinclaire\"", "\"Kaito Sinclaire\"",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
"\"katsy\"",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port "Ronald \"Furyhunter\" Kinard", // The SDL2 port
"\"Lat'\"", // SRB2-CHAT, the chat window from Kart "\"Lat'\"", // SRB2-CHAT, the chat window from Kart
"\"LZA\"", "\"LZA\"",
@ -3435,7 +3435,7 @@ void F_TitleScreenTicker(boolean run)
{ {
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
mo2 = (mobj_t *)th; mo2 = (mobj_t *)th;

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -444,12 +444,11 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
if (dent->d_type == DT_UNKNOWN) if (dent->d_type == DT_UNKNOWN || dent->d_type == DT_LNK)
if (lstat(searchpath,&fsstat) == 0 && S_ISDIR(fsstat.st_mode)) if (stat(searchpath,&fsstat) == 0 && S_ISDIR(fsstat.st_mode))
dent->d_type = DT_DIR; dent->d_type = DT_DIR;
// Linux and FreeBSD has a special field for file type on dirent, so use that to speed up lookups. // Linux and FreeBSD has a special field for file type on dirent, so use that to speed up lookups.
// FIXME: should we also follow symlinks?
if (dent->d_type == DT_DIR && depthleft) if (dent->d_type == DT_DIR && depthleft)
#else #else
if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -614,7 +614,7 @@ void G_ConsGhostTic(void)
mobj = NULL; mobj = NULL;
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
mobj = (mobj_t *)th; mobj = (mobj_t *)th;
if (mobj->type == (mobjtype_t)type && mobj->x == x && mobj->y == y && mobj->z == z) if (mobj->type == (mobjtype_t)type && mobj->x == x && mobj->y == y && mobj->z == z)
@ -1454,6 +1454,7 @@ void G_BeginRecording(void)
char *filename; char *filename;
UINT16 totalfiles; UINT16 totalfiles;
UINT8 *m; UINT8 *m;
save_t savebuffer;
if (demo_p) if (demo_p)
return; return;
@ -1603,7 +1604,11 @@ void G_BeginRecording(void)
} }
// Save netvar data // Save netvar data
CV_SaveDemoVars(&demo_p); savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_SaveDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldcmd,0,sizeof(oldcmd));
memset(&oldghost,0,sizeof(oldghost)); memset(&oldghost,0,sizeof(oldghost));
@ -2236,10 +2241,24 @@ void G_DoPlayDemo(char *defdemoname)
// net var data // net var data
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
if (demoversion < 0x000d) if (demoversion < 0x000d)
CV_LoadOldDemoVars(&demo_p); {
save_t savebuffer;
savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_LoadOldDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
}
else else
#endif #endif
CV_LoadDemoVars(&demo_p); {
save_t savebuffer;
savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_LoadDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
}
// Sigh ... it's an empty demo. // Sigh ... it's an empty demo.
if (*demo_p == DEMOMARKER) if (*demo_p == DEMOMARKER)
@ -2677,7 +2696,7 @@ void G_DoPlayMetal(void)
// find metal sonic // find metal sonic
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
mo = (mobj_t *)th; mo = (mobj_t *)th;

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -256,8 +256,6 @@ boolean precache = true; // if true, load all graphics at start
INT16 prevmap, nextmap; INT16 prevmap, nextmap;
static UINT8 *savebuffer;
// Analog Control // Analog Control
static void UserAnalog_OnChange(void); static void UserAnalog_OnChange(void);
static void UserAnalog2_OnChange(void); static void UserAnalog2_OnChange(void);
@ -1386,7 +1384,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0)) if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0))
cmd->buttons |= BT_SPIN; cmd->buttons |= BT_SPIN;
if (gamestate != GS_LEVEL) // not in a level, don't build anything else if (gamestate == GS_INTRO) // prevent crash in intro
{ {
cmd->angleturn = ticcmd_oldangleturn[forplayer]; cmd->angleturn = ticcmd_oldangleturn[forplayer];
cmd->aiming = G_ClipAimingPitch(myaiming); cmd->aiming = G_ClipAimingPitch(myaiming);
@ -1724,7 +1722,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// At this point, cmd doesn't contain the final angle yet, // At this point, cmd doesn't contain the final angle yet,
// So we need to temporarily transform it so Lua scripters // So we need to temporarily transform it so Lua scripters
// don't need to handle it differently than in other hooks. // don't need to handle it differently than in other hooks.
if (addedtogame) if (addedtogame && gamestate == GS_LEVEL)
{ {
INT16 extra = ticcmd_oldangleturn[forplayer] - player->oldrelangleturn; INT16 extra = ticcmd_oldangleturn[forplayer] - player->oldrelangleturn;
INT16 origangle = cmd->angleturn; INT16 origangle = cmd->angleturn;
@ -1936,6 +1934,8 @@ void G_DoLoadLevel(boolean resetplayer)
// //
void G_StartTitleCard(void) void G_StartTitleCard(void)
{ {
ST_stopTitleCard();
// The title card has been disabled for this map. // The title card has been disabled for this map.
// Oh well. // Oh well.
if (!G_IsTitleCardAvailable()) if (!G_IsTitleCardAvailable())
@ -2624,6 +2624,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
boolean spectator; boolean spectator;
boolean outofcoop; boolean outofcoop;
boolean removing; boolean removing;
boolean muted;
INT16 bot; INT16 bot;
SINT8 pity; SINT8 pity;
INT16 rings; INT16 rings;
@ -2641,6 +2642,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
spectator = players[player].spectator; spectator = players[player].spectator;
outofcoop = players[player].outofcoop; outofcoop = players[player].outofcoop;
removing = players[player].removing; removing = players[player].removing;
muted = players[player].muted;
pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER)); pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER));
playerangleturn = players[player].angleturn; playerangleturn = players[player].angleturn;
oldrelangleturn = players[player].oldrelangleturn; oldrelangleturn = players[player].oldrelangleturn;
@ -2718,6 +2720,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->spectator = spectator; p->spectator = spectator;
p->outofcoop = outofcoop; p->outofcoop = outofcoop;
p->removing = removing; p->removing = removing;
p->muted = muted;
p->angleturn = playerangleturn; p->angleturn = playerangleturn;
p->oldrelangleturn = oldrelangleturn; p->oldrelangleturn = oldrelangleturn;
@ -3069,7 +3072,7 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo)
// scan all thinkers // scan all thinkers
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
mo2 = (mobj_t *)th; mo2 = (mobj_t *)th;
@ -3352,7 +3355,7 @@ void G_AddPlayer(INT32 playernum)
p->playerstate = PST_REBORN; p->playerstate = PST_REBORN;
p->height = mobjinfo[MT_PLAYER].height; p->height = skins[p->skin]->height;
if (G_GametypeUsesLives() || ((netgame || multiplayer) && (gametyperules & GTR_FRIENDLY))) if (G_GametypeUsesLives() || ((netgame || multiplayer) && (gametyperules & GTR_FRIENDLY)))
p->lives = cv_startinglives.value; p->lives = cv_startinglives.value;
@ -4396,7 +4399,7 @@ void G_LoadGameSettings(void)
// Loads the main data file, which stores information such as emblems found, etc. // Loads the main data file, which stores information such as emblems found, etc.
void G_LoadGameData(gamedata_t *data) void G_LoadGameData(gamedata_t *data)
{ {
size_t length; save_t savebuffer;
INT32 i, j; INT32 i, j;
UINT32 versionID; UINT32 versionID;
@ -4438,18 +4441,18 @@ void G_LoadGameData(gamedata_t *data)
return; return;
} }
length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer); savebuffer.size = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer.buf);
if (!length) if (!savebuffer.size)
{ {
// No gamedata. We can save a new one. // No gamedata. We can save a new one.
data->loaded = true; data->loaded = true;
return; return;
} }
save_p = savebuffer; savebuffer.pos = 0;
// Version check // Version check
versionID = READUINT32(save_p); versionID = P_ReadUINT32(&savebuffer);
if (versionID != GAMEDATA_ID if (versionID != GAMEDATA_ID
#ifdef COMPAT_GAMEDATA_ID // backwards compat behavior #ifdef COMPAT_GAMEDATA_ID // backwards compat behavior
&& versionID != COMPAT_GAMEDATA_ID && versionID != COMPAT_GAMEDATA_ID
@ -4460,8 +4463,7 @@ void G_LoadGameData(gamedata_t *data)
if (strcmp(srb2home,".")) if (strcmp(srb2home,"."))
gdfolder = srb2home; gdfolder = srb2home;
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = NULL;
I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
} }
@ -4473,14 +4475,14 @@ void G_LoadGameData(gamedata_t *data)
} }
#endif #endif
data->totalplaytime = READUINT32(save_p); data->totalplaytime = P_ReadUINT32(&savebuffer);
#ifdef COMPAT_GAMEDATA_ID #ifdef COMPAT_GAMEDATA_ID
if (versionID == COMPAT_GAMEDATA_ID) if (versionID == COMPAT_GAMEDATA_ID)
{ {
// We'll temporarily use the old condition when loading an older file. // We'll temporarily use the old condition when loading an older file.
// The proper mod-specific hash will get saved in afterwards. // The proper mod-specific hash will get saved in afterwards.
boolean modded = READUINT8(save_p); boolean modded = P_ReadUINT8(&savebuffer);
if (modded && !savemoddata) if (modded && !savemoddata)
{ {
@ -4500,13 +4502,13 @@ void G_LoadGameData(gamedata_t *data)
strcpy(currentfilename, gamedatafilename); strcpy(currentfilename, gamedatafilename);
STRBUFCPY(backupfilename, strcat(currentfilename, bak)); STRBUFCPY(backupfilename, strcat(currentfilename, bak));
FIL_WriteFile(va(pandf, srb2home, backupfilename), savebuffer, length); FIL_WriteFile(va(pandf, srb2home, backupfilename), &savebuffer.buf, savebuffer.size);
} }
else else
#endif #endif
{ {
// Quick & dirty hash for what mod this save file is for. // Quick & dirty hash for what mod this save file is for.
UINT32 modID = READUINT32(save_p); UINT32 modID = P_ReadUINT32(&savebuffer);
UINT32 expectedID = quickncasehash(timeattackfolder, sizeof timeattackfolder); UINT32 expectedID = quickncasehash(timeattackfolder, sizeof timeattackfolder);
if (modID != expectedID) if (modID != expectedID)
@ -4518,50 +4520,50 @@ void G_LoadGameData(gamedata_t *data)
// TODO put another cipher on these things? meh, I don't care... // TODO put another cipher on these things? meh, I don't care...
for (i = 0; i < NUMMAPS; i++) for (i = 0; i < NUMMAPS; i++)
if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) if ((data->mapvisited[i] = P_ReadUINT8(&savebuffer)) > MV_MAX)
goto datacorrupt; goto datacorrupt;
// To save space, use one bit per collected/achieved/unlocked flag // To save space, use one bit per collected/achieved/unlocked flag
for (i = 0; i < max_emblems;) for (i = 0; i < max_emblems;)
{ {
rtemp = READUINT8(save_p); rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_emblems; ++j) for (j = 0; j < 8 && j+i < max_emblems; ++j)
data->collected[j+i] = ((rtemp >> j) & 1); data->collected[j+i] = ((rtemp >> j) & 1);
i += j; i += j;
} }
for (i = 0; i < max_extraemblems;) for (i = 0; i < max_extraemblems;)
{ {
rtemp = READUINT8(save_p); rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_extraemblems; ++j) for (j = 0; j < 8 && j+i < max_extraemblems; ++j)
data->extraCollected[j+i] = ((rtemp >> j) & 1); data->extraCollected[j+i] = ((rtemp >> j) & 1);
i += j; i += j;
} }
for (i = 0; i < max_unlockables;) for (i = 0; i < max_unlockables;)
{ {
rtemp = READUINT8(save_p); rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_unlockables; ++j) for (j = 0; j < 8 && j+i < max_unlockables; ++j)
data->unlocked[j+i] = ((rtemp >> j) & 1); data->unlocked[j+i] = ((rtemp >> j) & 1);
i += j; i += j;
} }
for (i = 0; i < max_conditionsets;) for (i = 0; i < max_conditionsets;)
{ {
rtemp = READUINT8(save_p); rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_conditionsets; ++j) for (j = 0; j < 8 && j+i < max_conditionsets; ++j)
data->achieved[j+i] = ((rtemp >> j) & 1); data->achieved[j+i] = ((rtemp >> j) & 1);
i += j; i += j;
} }
data->timesBeaten = READUINT32(save_p); data->timesBeaten = P_ReadUINT32(&savebuffer);
data->timesBeatenWithEmeralds = READUINT32(save_p); data->timesBeatenWithEmeralds = P_ReadUINT32(&savebuffer);
data->timesBeatenUltimate = READUINT32(save_p); data->timesBeatenUltimate = P_ReadUINT32(&savebuffer);
// Main records // Main records
for (i = 0; i < NUMMAPS; ++i) for (i = 0; i < NUMMAPS; ++i)
{ {
recscore = READUINT32(save_p); recscore = P_ReadUINT32(&savebuffer);
rectime = (tic_t)READUINT32(save_p); rectime = (tic_t)P_ReadUINT32(&savebuffer);
recrings = READUINT16(save_p); recrings = P_ReadUINT16(&savebuffer);
save_p++; // compat P_ReadUINT8(&savebuffer); // compat
if (recrings > 10000 || recscore > MAXSCORE) if (recrings > 10000 || recscore > MAXSCORE)
goto datacorrupt; goto datacorrupt;
@ -4578,16 +4580,16 @@ void G_LoadGameData(gamedata_t *data)
// Nights records // Nights records
for (i = 0; i < NUMMAPS; ++i) for (i = 0; i < NUMMAPS; ++i)
{ {
if ((recmares = READUINT8(save_p)) == 0) if ((recmares = P_ReadUINT8(&savebuffer)) == 0)
continue; continue;
G_AllocNightsRecordData((INT16)i, data); G_AllocNightsRecordData((INT16)i, data);
for (curmare = 0; curmare < (recmares+1); ++curmare) for (curmare = 0; curmare < (recmares+1); ++curmare)
{ {
data->nightsrecords[i]->score[curmare] = READUINT32(save_p); data->nightsrecords[i]->score[curmare] = P_ReadUINT32(&savebuffer);
data->nightsrecords[i]->grade[curmare] = READUINT8(save_p); data->nightsrecords[i]->grade[curmare] = P_ReadUINT8(&savebuffer);
data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p); data->nightsrecords[i]->time[curmare] = (tic_t)P_ReadUINT32(&savebuffer);
if (data->nightsrecords[i]->grade[curmare] > GRADE_S) if (data->nightsrecords[i]->grade[curmare] > GRADE_S)
{ {
@ -4599,8 +4601,7 @@ void G_LoadGameData(gamedata_t *data)
} }
// done // done
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = NULL;
// Don't consider loaded until it's a success! // Don't consider loaded until it's a success!
// It used to do this much earlier, but this would cause the gamedata to // It used to do this much earlier, but this would cause the gamedata to
@ -4621,8 +4622,7 @@ void G_LoadGameData(gamedata_t *data)
if (strcmp(srb2home,".")) if (strcmp(srb2home,"."))
gdfolder = srb2home; gdfolder = srb2home;
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = NULL;
I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
} }
@ -4632,9 +4632,8 @@ void G_LoadGameData(gamedata_t *data)
// Saves the main data file, which stores information such as emblems found, etc. // Saves the main data file, which stores information such as emblems found, etc.
void G_SaveGameData(gamedata_t *data) void G_SaveGameData(gamedata_t *data)
{ {
UINT8 *data_p; save_t savebuffer;
size_t length;
INT32 i, j; INT32 i, j;
UINT8 btemp; UINT8 btemp;
@ -4646,30 +4645,31 @@ void G_SaveGameData(gamedata_t *data)
if (!data->loaded) if (!data->loaded)
return; // If never loaded (-nodata), don't save return; // If never loaded (-nodata), don't save
data_p = savebuffer = (UINT8 *)malloc(GAMEDATASIZE); savebuffer.size = GAMEDATASIZE;
if (!data_p) savebuffer.buf = (UINT8 *)malloc(savebuffer.size);
if (!savebuffer.buf)
{ {
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
return; return;
} }
savebuffer.pos = 0;
if (usedCheats) if (usedCheats)
{ {
free(savebuffer); free(savebuffer.buf);
savebuffer = NULL;
return; return;
} }
// Version test // Version test
WRITEUINT32(data_p, GAMEDATA_ID); P_WriteUINT32(&savebuffer, GAMEDATA_ID);
WRITEUINT32(data_p, data->totalplaytime); P_WriteUINT32(&savebuffer, data->totalplaytime);
WRITEUINT32(data_p, quickncasehash(timeattackfolder, sizeof timeattackfolder)); P_WriteUINT32(&savebuffer, quickncasehash(timeattackfolder, sizeof timeattackfolder));
// TODO put another cipher on these things? meh, I don't care... // TODO put another cipher on these things? meh, I don't care...
for (i = 0; i < NUMMAPS; i++) for (i = 0; i < NUMMAPS; i++)
WRITEUINT8(data_p, (data->mapvisited[i] & MV_MAX)); P_WriteUINT8(&savebuffer, (data->mapvisited[i] & MV_MAX));
// To save space, use one bit per collected/achieved/unlocked flag // To save space, use one bit per collected/achieved/unlocked flag
for (i = 0; i < MAXEMBLEMS;) for (i = 0; i < MAXEMBLEMS;)
@ -4677,7 +4677,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0; btemp = 0;
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
btemp |= (data->collected[j+i] << j); btemp |= (data->collected[j+i] << j);
WRITEUINT8(data_p, btemp); P_WriteUINT8(&savebuffer, btemp);
i += j; i += j;
} }
for (i = 0; i < MAXEXTRAEMBLEMS;) for (i = 0; i < MAXEXTRAEMBLEMS;)
@ -4685,7 +4685,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0; btemp = 0;
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
btemp |= (data->extraCollected[j+i] << j); btemp |= (data->extraCollected[j+i] << j);
WRITEUINT8(data_p, btemp); P_WriteUINT8(&savebuffer, btemp);
i += j; i += j;
} }
for (i = 0; i < MAXUNLOCKABLES;) for (i = 0; i < MAXUNLOCKABLES;)
@ -4693,7 +4693,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0; btemp = 0;
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
btemp |= (data->unlocked[j+i] << j); btemp |= (data->unlocked[j+i] << j);
WRITEUINT8(data_p, btemp); P_WriteUINT8(&savebuffer, btemp);
i += j; i += j;
} }
for (i = 0; i < MAXCONDITIONSETS;) for (i = 0; i < MAXCONDITIONSETS;)
@ -4701,30 +4701,30 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0; btemp = 0;
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
btemp |= (data->achieved[j+i] << j); btemp |= (data->achieved[j+i] << j);
WRITEUINT8(data_p, btemp); P_WriteUINT8(&savebuffer, btemp);
i += j; i += j;
} }
WRITEUINT32(data_p, data->timesBeaten); P_WriteUINT32(&savebuffer, data->timesBeaten);
WRITEUINT32(data_p, data->timesBeatenWithEmeralds); P_WriteUINT32(&savebuffer, data->timesBeatenWithEmeralds);
WRITEUINT32(data_p, data->timesBeatenUltimate); P_WriteUINT32(&savebuffer, data->timesBeatenUltimate);
// Main records // Main records
for (i = 0; i < NUMMAPS; i++) for (i = 0; i < NUMMAPS; i++)
{ {
if (data->mainrecords[i]) if (data->mainrecords[i])
{ {
WRITEUINT32(data_p, data->mainrecords[i]->score); P_WriteUINT32(&savebuffer, data->mainrecords[i]->score);
WRITEUINT32(data_p, data->mainrecords[i]->time); P_WriteUINT32(&savebuffer, data->mainrecords[i]->time);
WRITEUINT16(data_p, data->mainrecords[i]->rings); P_WriteUINT16(&savebuffer, data->mainrecords[i]->rings);
} }
else else
{ {
WRITEUINT32(data_p, 0); P_WriteUINT32(&savebuffer, 0);
WRITEUINT32(data_p, 0); P_WriteUINT32(&savebuffer, 0);
WRITEUINT16(data_p, 0); P_WriteUINT16(&savebuffer, 0);
} }
WRITEUINT8(data_p, 0); // compat P_WriteUINT8(&savebuffer, 0); // compat
} }
// NiGHTS records // NiGHTS records
@ -4732,25 +4732,22 @@ void G_SaveGameData(gamedata_t *data)
{ {
if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares) if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares)
{ {
WRITEUINT8(data_p, 0); P_WriteUINT8(&savebuffer, 0);
continue; continue;
} }
WRITEUINT8(data_p, data->nightsrecords[i]->nummares); P_WriteUINT8(&savebuffer, data->nightsrecords[i]->nummares);
for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare) for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare)
{ {
WRITEUINT32(data_p, data->nightsrecords[i]->score[curmare]); P_WriteUINT32(&savebuffer, data->nightsrecords[i]->score[curmare]);
WRITEUINT8(data_p, data->nightsrecords[i]->grade[curmare]); P_WriteUINT8(&savebuffer, data->nightsrecords[i]->grade[curmare]);
WRITEUINT32(data_p, data->nightsrecords[i]->time[curmare]); P_WriteUINT32(&savebuffer, data->nightsrecords[i]->time[curmare]);
} }
} }
length = data_p - savebuffer; FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer.buf, savebuffer.pos);
free(savebuffer.buf);
FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer, length);
free(savebuffer);
savebuffer = NULL;
} }
#define VERSIONSIZE 16 #define VERSIONSIZE 16
@ -4761,7 +4758,7 @@ void G_SaveGameData(gamedata_t *data)
// //
void G_LoadGame(UINT32 slot, INT16 mapoverride) void G_LoadGame(UINT32 slot, INT16 mapoverride)
{ {
size_t length; save_t savebuffer;
char vcheck[VERSIONSIZE]; char vcheck[VERSIONSIZE];
char savename[255]; char savename[255];
@ -4778,18 +4775,18 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
else else
sprintf(savename, savegamename, slot); sprintf(savename, savegamename, slot);
length = FIL_ReadFile(savename, &savebuffer); savebuffer.size = FIL_ReadFile(savename, &savebuffer.buf);
if (!length) if (!savebuffer.size)
{ {
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
return; return;
} }
save_p = savebuffer; savebuffer.pos = 0;
memset(vcheck, 0, sizeof (vcheck)); memset(vcheck, 0, sizeof (vcheck));
sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION);
if (strcmp((const char *)save_p, (const char *)vcheck)) if (strcmp((const char *)&savebuffer.buf[savebuffer.pos], (const char *)vcheck))
{ {
#ifdef SAVEGAME_OTHERVERSIONS #ifdef SAVEGAME_OTHERVERSIONS
M_StartMessage(M_GetText("Save game from different version.\nYou can load this savegame, but\nsaving afterwards will be disabled.\n\nDo you want to continue anyway?\n\n(Press 'Y' to confirm)\n"), M_StartMessage(M_GetText("Save game from different version.\nYou can load this savegame, but\nsaving afterwards will be disabled.\n\nDo you want to continue anyway?\n\n(Press 'Y' to confirm)\n"),
@ -4799,15 +4796,14 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
M_ClearMenus(true); // so ESC backs out to title M_ClearMenus(true); // so ESC backs out to title
M_StartMessage(M_GetText("Save game from different version\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("Save game from different version\n\nPress ESC\n"), NULL, MM_NOTHING);
Command_ExitGame_f(); Command_ExitGame_f();
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = NULL;
// no cheating! // no cheating!
memset(&savedata, 0, sizeof(savedata)); memset(&savedata, 0, sizeof(savedata));
#endif #endif
return; // bad version return; // bad version
} }
save_p += VERSIONSIZE; savebuffer.pos += VERSIONSIZE;
// if (demoplayback) // reset game engine // if (demoplayback) // reset game engine
// G_StopDemo(); // G_StopDemo();
@ -4816,13 +4812,12 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
// automapactive = false; // automapactive = false;
// dearchive all the modifications // dearchive all the modifications
if (!P_LoadGame(mapoverride)) if (!P_LoadGame(&savebuffer, mapoverride))
{ {
M_ClearMenus(true); // so ESC backs out to title M_ClearMenus(true); // so ESC backs out to title
M_StartMessage(M_GetText("Savegame file corrupted\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("Savegame file corrupted\n\nPress ESC\n"), NULL, MM_NOTHING);
Command_ExitGame_f(); Command_ExitGame_f();
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = NULL;
// no cheating! // no cheating!
memset(&savedata, 0, sizeof(savedata)); memset(&savedata, 0, sizeof(savedata));
@ -4830,13 +4825,12 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
} }
if (marathonmode) if (marathonmode)
{ {
marathontime = READUINT32(save_p); marathontime = P_ReadUINT32(&savebuffer);
marathonmode |= READUINT8(save_p); marathonmode |= P_ReadUINT8(&savebuffer);
} }
// done // done
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = NULL;
displayplayer = consoleplayer; displayplayer = consoleplayer;
multiplayer = splitscreen = false; multiplayer = splitscreen = false;
@ -4854,6 +4848,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
// //
void G_SaveGame(UINT32 slot, INT16 mapnum) void G_SaveGame(UINT32 slot, INT16 mapnum)
{ {
save_t savebuffer;
boolean saved; boolean saved;
char savename[256] = ""; char savename[256] = "";
const char *backup; const char *backup;
@ -4867,33 +4862,32 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
gameaction = ga_nothing; gameaction = ga_nothing;
{ {
char name[VERSIONSIZE]; char name[VERSIONSIZE];
size_t length;
save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); savebuffer.size = SAVEGAMESIZE;
if (!save_p) savebuffer.buf = (UINT8 *)malloc(savebuffer.size);
if (!savebuffer.buf)
{ {
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
return; return;
} }
savebuffer.pos = 0;
memset(name, 0, sizeof (name)); memset(name, 0, sizeof (name));
sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION); sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION);
WRITEMEM(save_p, name, VERSIONSIZE); P_WriteMem(&savebuffer, name, VERSIONSIZE);
P_SaveGame(mapnum); P_SaveGame(&savebuffer, mapnum);
if (marathonmode) if (marathonmode)
{ {
UINT32 writetime = marathontime; UINT32 writetime = marathontime;
if (!(marathonmode & MA_INGAME)) if (!(marathonmode & MA_INGAME))
writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map
WRITEUINT32(save_p, writetime); P_WriteUINT32(&savebuffer, writetime);
WRITEUINT8(save_p, (marathonmode & ~MA_INIT)); P_WriteUINT8(&savebuffer, (marathonmode & ~MA_INIT));
} }
length = save_p - savebuffer; saved = FIL_WriteFile(backup, savebuffer.buf, savebuffer.pos);
saved = FIL_WriteFile(backup, savebuffer, length); free(savebuffer.buf);
free(savebuffer);
save_p = savebuffer = NULL;
} }
gameaction = ga_nothing; gameaction = ga_nothing;
@ -4905,11 +4899,10 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
} }
#define BADSAVE goto cleanup; #define BADSAVE goto cleanup;
#define CHECKPOS if (save_p >= end_p) BADSAVE
void G_SaveGameOver(UINT32 slot, boolean modifylives) void G_SaveGameOver(UINT32 slot, boolean modifylives)
{ {
save_t savebuffer;
boolean saved = false; boolean saved = false;
size_t length;
char vcheck[VERSIONSIZE]; char vcheck[VERSIONSIZE];
char savename[255]; char savename[255];
const char *backup; const char *backup;
@ -4920,42 +4913,38 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
sprintf(savename, savegamename, slot); sprintf(savename, savegamename, slot);
backup = va("%s",savename); backup = va("%s",savename);
length = FIL_ReadFile(savename, &savebuffer); savebuffer.size = FIL_ReadFile(savename, &savebuffer.buf);
if (!length) if (!savebuffer.size)
{ {
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
return; return;
} }
savebuffer.pos = 0;
{ {
char temp[sizeof(timeattackfolder)]; char temp[sizeof(timeattackfolder)];
UINT8 *end_p = savebuffer + length;
UINT8 *lives_p; UINT8 *lives_p;
SINT8 pllives; SINT8 pllives;
#ifdef NEWSKINSAVES #ifdef NEWSKINSAVES
INT16 backwardsCompat = 0; INT16 backwardsCompat = 0;
#endif #endif
save_p = savebuffer;
// Version check // Version check
memset(vcheck, 0, sizeof (vcheck)); memset(vcheck, 0, sizeof (vcheck));
sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION);
if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE if (strcmp((const char *)&savebuffer.buf[savebuffer.pos], (const char *)vcheck)) BADSAVE
save_p += VERSIONSIZE; savebuffer.pos += VERSIONSIZE;
// P_UnArchiveMisc() // P_UnArchiveMisc()
(void)READINT16(save_p); (void)P_ReadINT16(&savebuffer);
CHECKPOS (void)P_ReadUINT16(&savebuffer); // emeralds
(void)READUINT16(save_p); // emeralds P_ReadStringN(&savebuffer, temp, sizeof(temp)); // mod it belongs to
CHECKPOS
READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to
if (strcmp(temp, timeattackfolder)) BADSAVE if (strcmp(temp, timeattackfolder)) BADSAVE
// P_UnArchivePlayer() // P_UnArchivePlayer()
CHECKPOS
#ifdef NEWSKINSAVES #ifdef NEWSKINSAVES
backwardsCompat = READUINT16(save_p); backwardsCompat = P_ReadUINT16(&savebuffer);
CHECKPOS
if (backwardsCompat == NEWSKINSAVES) // New save, read skin names if (backwardsCompat == NEWSKINSAVES) // New save, read skin names
#endif #endif
@ -4963,47 +4952,37 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
char ourSkinName[SKINNAMESIZE+1]; char ourSkinName[SKINNAMESIZE+1];
char botSkinName[SKINNAMESIZE+1]; char botSkinName[SKINNAMESIZE+1];
READSTRINGN(save_p, ourSkinName, SKINNAMESIZE); P_ReadStringN(&savebuffer, ourSkinName, SKINNAMESIZE);
CHECKPOS
READSTRINGN(save_p, botSkinName, SKINNAMESIZE); P_ReadStringN(&savebuffer, botSkinName, SKINNAMESIZE);
CHECKPOS
} }
WRITEUINT8(save_p, numgameovers); P_WriteUINT8(&savebuffer, numgameovers);
CHECKPOS
lives_p = save_p; lives_p = &savebuffer.buf[savebuffer.pos];
pllives = READSINT8(save_p); // lives pllives = P_ReadSINT8(&savebuffer); // lives
CHECKPOS
if (modifylives && pllives < startinglivesbalance[numgameovers]) if (modifylives && pllives < startinglivesbalance[numgameovers])
{ {
pllives = startinglivesbalance[numgameovers]; *lives_p = startinglivesbalance[numgameovers];
WRITESINT8(lives_p, pllives);
} }
(void)READINT32(save_p); // Score (void)P_ReadINT32(&savebuffer); // Score
CHECKPOS (void)P_ReadINT32(&savebuffer); // continues
(void)READINT32(save_p); // continues
// File end marker check // File end marker check
CHECKPOS switch (P_ReadUINT8(&savebuffer))
switch (READUINT8(save_p))
{ {
case 0xb7: case 0xb7:
{ {
UINT8 i, banksinuse; UINT8 i, banksinuse;
CHECKPOS banksinuse = P_ReadUINT8(&savebuffer);
banksinuse = READUINT8(save_p);
CHECKPOS
if (banksinuse > NUM_LUABANKS) if (banksinuse > NUM_LUABANKS)
BADSAVE BADSAVE
for (i = 0; i < banksinuse; i++) for (i = 0; i < banksinuse; i++)
{ {
(void)READINT32(save_p); (void)P_ReadINT32(&savebuffer);
CHECKPOS
} }
if (READUINT8(save_p) != 0x1d) if (P_ReadUINT8(&savebuffer) != 0x1d)
BADSAVE BADSAVE
} }
case 0x1d: case 0x1d:
@ -5013,7 +4992,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
} }
// done // done
saved = FIL_WriteFile(backup, savebuffer, length); saved = FIL_WriteFile(backup, savebuffer.buf, savebuffer.size);
} }
cleanup: cleanup:
@ -5021,11 +5000,9 @@ cleanup:
CONS_Printf(M_GetText("Game saved.\n")); CONS_Printf(M_GetText("Game saved.\n"));
else if (!saved) else if (!saved)
CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename)); CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename));
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = NULL;
} }
#undef CHECKPOS
#undef BADSAVE #undef BADSAVE
// //

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Sonic Team Junior. // Copyright (C) 2020-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -114,7 +114,7 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt
polygonArray[polygonArraySize].numVerts = iNumPts; polygonArray[polygonArraySize].numVerts = iNumPts;
polygonArray[polygonArraySize].polyFlags = PolyFlags; polygonArray[polygonArraySize].polyFlags = PolyFlags;
polygonArray[polygonArraySize].texture = current_texture; polygonArray[polygonArraySize].texture = current_texture;
polygonArray[polygonArraySize].shader = (shader_target != -1) ? HWR_GetShaderFromTarget(shader_target) : shader_target; polygonArray[polygonArraySize].shader = (shader_target != SHADER_NONE) ? HWR_GetShaderFromTarget(shader_target) : shader_target;
polygonArray[polygonArraySize].horizonSpecial = horizonSpecial; polygonArray[polygonArraySize].horizonSpecial = horizonSpecial;
// default to polygonArraySize so we don't lose order on horizon lines // default to polygonArraySize so we don't lose order on horizon lines
// (yes, it's supposed to be negative, since we're sorting in that direction) // (yes, it's supposed to be negative, since we're sorting in that direction)
@ -311,7 +311,6 @@ void HWR_RenderBatches(void)
int nextIndex = polygonIndexArray[polygonReadPos]; int nextIndex = polygonIndexArray[polygonReadPos];
if (polygonArray[index].hash != polygonArray[nextIndex].hash) if (polygonArray[index].hash != polygonArray[nextIndex].hash)
{ {
changeState = true;
nextShader = polygonArray[nextIndex].shader; nextShader = polygonArray[nextIndex].shader;
nextTexture = polygonArray[nextIndex].texture; nextTexture = polygonArray[nextIndex].texture;
nextPolyFlags = polygonArray[nextIndex].polyFlags; nextPolyFlags = polygonArray[nextIndex].polyFlags;
@ -320,14 +319,17 @@ void HWR_RenderBatches(void)
nextTexture = 0; nextTexture = 0;
if (currentShader != nextShader && cv_glshaders.value && gl_shadersavailable) if (currentShader != nextShader && cv_glshaders.value && gl_shadersavailable)
{ {
changeState = true;
changeShader = true; changeShader = true;
} }
if (currentTexture != nextTexture) if (currentTexture != nextTexture)
{ {
changeState = true;
changeTexture = true; changeTexture = true;
} }
if (currentPolyFlags != nextPolyFlags) if (currentPolyFlags != nextPolyFlags)
{ {
changeState = true;
changePolyFlags = true; changePolyFlags = true;
} }
if (cv_glshaders.value && gl_shadersavailable) if (cv_glshaders.value && gl_shadersavailable)
@ -339,6 +341,7 @@ void HWR_RenderBatches(void)
currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start || currentSurfaceInfo.LightInfo.fade_start != nextSurfaceInfo.LightInfo.fade_start ||
currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end) currentSurfaceInfo.LightInfo.fade_end != nextSurfaceInfo.LightInfo.fade_end)
{ {
changeState = true;
changeSurfaceInfo = true; changeSurfaceInfo = true;
} }
} }
@ -346,6 +349,7 @@ void HWR_RenderBatches(void)
{ {
if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba) if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba)
{ {
changeState = true;
changeSurfaceInfo = true; changeSurfaceInfo = true;
} }
} }

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Sonic Team Junior. // Copyright (C) 2020-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -450,15 +450,10 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex, GLMipmap_t
texture = textures[texnum]; texture = textures[texnum];
mipmap->flags = TF_WRAPXY;
mipmap->width = (UINT16)texture->width;
mipmap->height = (UINT16)texture->height;
mipmap->format = textureformat;
blockwidth = texture->width; blockwidth = texture->width;
blockheight = texture->height; blockheight = texture->height;
blocksize = (blockwidth * blockheight); blocksize = blockwidth * blockheight;
block = MakeBlock(&grtex->mipmap); block = MakeBlock(mipmap);
// Composite the columns together. // Composite the columns together.
for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++)
@ -488,7 +483,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex, GLMipmap_t
realpatch = W_CachePatchNumPwad(wadnum, lumpnum, PU_PATCH); realpatch = W_CachePatchNumPwad(wadnum, lumpnum, PU_PATCH);
} }
HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch); HWR_DrawTexturePatchInCache(mipmap, blockwidth, blockheight, texture, patch, realpatch);
if (free_patch) if (free_patch)
Patch_Free(realpatch); Patch_Free(realpatch);
@ -680,25 +675,24 @@ void HWR_InitMapTextures(void)
gl_maptexturesloaded = false; gl_maptexturesloaded = false;
} }
static void DeleteTextureMipmap(GLMipmap_t *grMipmap) static void DeleteTextureMipmap(GLMipmap_t *grMipmap, boolean delete_mipmap)
{ {
HWD.pfnDeleteTexture(grMipmap); HWD.pfnDeleteTexture(grMipmap);
// Chroma-keyed textures do not own their texture data, so do not free it if (delete_mipmap)
if (!(grMipmap->flags & TF_CHROMAKEYED))
Z_Free(grMipmap->data); Z_Free(grMipmap->data);
} }
static void FreeMapTexture(GLMapTexture_t *tex) static void FreeMapTexture(GLMapTexture_t *tex, boolean delete_chromakeys)
{ {
if (tex->mipmap.nextcolormap) if (tex->mipmap.nextcolormap)
{ {
DeleteTextureMipmap(tex->mipmap.nextcolormap); DeleteTextureMipmap(tex->mipmap.nextcolormap, delete_chromakeys);
free(tex->mipmap.nextcolormap); free(tex->mipmap.nextcolormap);
tex->mipmap.nextcolormap = NULL; tex->mipmap.nextcolormap = NULL;
} }
DeleteTextureMipmap(&tex->mipmap); DeleteTextureMipmap(&tex->mipmap, true);
} }
void HWR_FreeMapTextures(void) void HWR_FreeMapTextures(void)
@ -707,8 +701,8 @@ void HWR_FreeMapTextures(void)
for (i = 0; i < gl_numtextures; i++) for (i = 0; i < gl_numtextures; i++)
{ {
FreeMapTexture(&gl_textures[i]); FreeMapTexture(&gl_textures[i], true);
FreeMapTexture(&gl_flats[i]); FreeMapTexture(&gl_flats[i], false);
} }
// now the heap don't have any 'user' pointing to our // now the heap don't have any 'user' pointing to our
@ -741,22 +735,7 @@ void HWR_LoadMapTextures(size_t pnumtextures)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Make sure texture is downloaded and set it as the source // Make sure texture is downloaded and set it as the source
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
static void GetMapTexture(INT32 tex, GLMapTexture_t *grtex, GLMipmap_t *mipmap) GLMapTexture_t *HWR_GetTexture(INT32 tex, boolean chromakeyed)
{
// Generate texture if missing from the cache
if (!mipmap->data && !mipmap->downloaded)
HWR_GenerateTexture(tex, grtex, mipmap);
// If hardware does not have the texture, then call pfnSetTexture to upload it
if (!mipmap->downloaded)
HWD.pfnSetTexture(mipmap);
HWR_SetCurrentTexture(mipmap);
// The system-memory data can be purged now.
Z_ChangeTag(mipmap->data, PU_HWRCACHE_UNLOCKED);
}
GLMapTexture_t *HWR_GetTexture(INT32 tex)
{ {
if (tex < 0 || tex >= (signed)gl_numtextures) if (tex < 0 || tex >= (signed)gl_numtextures)
{ {
@ -769,7 +748,46 @@ GLMapTexture_t *HWR_GetTexture(INT32 tex)
GLMapTexture_t *grtex = &gl_textures[tex]; GLMapTexture_t *grtex = &gl_textures[tex];
GetMapTexture(tex, grtex, &grtex->mipmap); GLMipmap_t *grMipmap = &grtex->mipmap;
GLMipmap_t *originalMipmap = grMipmap;
if (!originalMipmap->downloaded)
{
originalMipmap->flags = TF_WRAPXY;
originalMipmap->width = (UINT16)textures[tex]->width;
originalMipmap->height = (UINT16)textures[tex]->height;
originalMipmap->format = textureformat;
}
// If chroma-keyed, create or use a different mipmap for the variant
if (chromakeyed && !textures[tex]->transparency)
{
// Allocate it if it wasn't already
if (!originalMipmap->nextcolormap)
{
GLMipmap_t *newMipmap = calloc(1, sizeof (*grMipmap));
if (newMipmap == NULL)
I_Error("%s: Out of memory", "HWR_GetTexture");
newMipmap->flags = originalMipmap->flags | TF_CHROMAKEYED;
newMipmap->width = originalMipmap->width;
newMipmap->height = originalMipmap->height;
newMipmap->format = originalMipmap->format;
originalMipmap->nextcolormap = newMipmap;
}
// Generate, upload and bind the variant texture instead of the original one
grMipmap = originalMipmap->nextcolormap;
}
if (!grMipmap->data)
HWR_GenerateTexture(tex, grtex, grMipmap);
if (!grMipmap->downloaded)
HWD.pfnSetTexture(grMipmap);
HWR_SetCurrentTexture(grMipmap);
Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED);
return grtex; return grtex;
} }
@ -1240,20 +1258,29 @@ void HWR_SetMapPalette(void)
// Creates a hardware lighttable from the supplied lighttable. // Creates a hardware lighttable from the supplied lighttable.
// Returns the id of the hw lighttable, usable in FSurfaceInfo. // Returns the id of the hw lighttable, usable in FSurfaceInfo.
UINT32 HWR_CreateLightTable(UINT8 *lighttable) UINT32 HWR_CreateLightTable(UINT8 *lighttable, RGBA_t *hw_lighttable)
{ {
UINT32 i, id; UINT32 i;
RGBA_t *palette = HWR_GetTexturePalette(); RGBA_t *palette = HWR_GetTexturePalette();
RGBA_t *hw_lighttable = Z_Malloc(256 * 32 * sizeof(RGBA_t), PU_STATIC, NULL);
// To make the palette index -> RGBA mapping easier for the shader, // To make the palette index -> RGBA mapping easier for the shader,
// the hardware lighttable is composed of RGBA colors instead of palette indices. // the hardware lighttable is composed of RGBA colors instead of palette indices.
for (i = 0; i < 256 * 32; i++) for (i = 0; i < 256 * 32; i++)
hw_lighttable[i] = palette[lighttable[i]]; hw_lighttable[i] = palette[lighttable[i]];
id = HWD.pfnCreateLightTable(hw_lighttable); return HWD.pfnCreateLightTable(hw_lighttable);
Z_Free(hw_lighttable); }
return id;
// Updates a hardware lighttable of a given id from the supplied lighttable.
void HWR_UpdateLightTable(UINT32 id, UINT8 *lighttable, RGBA_t *hw_lighttable)
{
UINT32 i;
RGBA_t *palette = HWR_GetTexturePalette();
for (i = 0; i < 256 * 32; i++)
hw_lighttable[i] = palette[lighttable[i]];
HWD.pfnUpdateLightTable(id, hw_lighttable);
} }
// get hwr lighttable id for colormap, create it if it doesn't already exist // get hwr lighttable id for colormap, create it if it doesn't already exist
@ -1267,25 +1294,41 @@ UINT32 HWR_GetLightTableID(extracolormap_t *colormap)
default_colormap = true; default_colormap = true;
} }
// create hw lighttable if there isn't one UINT8 *colormap_pointer;
if (!colormap->gl_lighttable_id)
{
UINT8 *colormap_pointer;
if (default_colormap) if (default_colormap)
colormap_pointer = colormaps; // don't actually use the data from the "default colormap" colormap_pointer = colormaps; // don't actually use the data from the "default colormap"
else else
colormap_pointer = colormap->colormap; colormap_pointer = colormap->colormap;
colormap->gl_lighttable_id = HWR_CreateLightTable(colormap_pointer);
// create hw lighttable if there isn't one
if (colormap->gl_lighttable.data == NULL)
{
Z_Malloc(256 * 32 * sizeof(RGBA_t), PU_HWRLIGHTTABLEDATA, &colormap->gl_lighttable.data);
} }
return colormap->gl_lighttable_id; // Generate the texture for this light table
if (!colormap->gl_lighttable.id)
{
colormap->gl_lighttable.id = HWR_CreateLightTable(colormap_pointer, colormap->gl_lighttable.data);
}
// Update the texture if it was directly changed by a script
else if (colormap->gl_lighttable.needs_update)
{
HWR_UpdateLightTable(colormap->gl_lighttable.id, colormap_pointer, colormap->gl_lighttable.data);
}
colormap->gl_lighttable.needs_update = false;
return colormap->gl_lighttable.id;
} }
// Note: all hardware lighttable ids assigned before this // Note: all hardware lighttable ids assigned before this
// call become invalid and must not be used. // call become invalid and must not be used.
void HWR_ClearLightTables(void) void HWR_ClearLightTables(void)
{ {
Z_FreeTag(PU_HWRLIGHTTABLEDATA);
if (vid.glstate == VID_GL_LIBRARY_LOADED) if (vid.glstate == VID_GL_LIBRARY_LOADED)
HWD.pfnClearLightTables(); HWD.pfnClearLightTables();
} }

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -71,6 +71,7 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value);
EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut); EXPORT void HWRAPI(SetPaletteLookup)(UINT8 *lut);
EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable); EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable);
EXPORT void HWRAPI(UpdateLightTable)(UINT32 id, RGBA_t *hw_lighttable);
EXPORT void HWRAPI(ClearLightTables)(void); EXPORT void HWRAPI(ClearLightTables)(void);
EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette); EXPORT void HWRAPI(SetScreenPalette)(RGBA_t *palette);
@ -125,6 +126,7 @@ struct hwdriver_s
SetPaletteLookup pfnSetPaletteLookup; SetPaletteLookup pfnSetPaletteLookup;
CreateLightTable pfnCreateLightTable; CreateLightTable pfnCreateLightTable;
UpdateLightTable pfnUpdateLightTable;
ClearLightTables pfnClearLightTables; ClearLightTables pfnClearLightTables;
SetScreenPalette pfnSetScreenPalette; SetScreenPalette pfnSetScreenPalette;
}; };

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -120,7 +120,7 @@ void HWR_GetPatch(patch_t *patch);
void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap); void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap);
void HWR_GetFadeMask(lumpnum_t fademasklumpnum); void HWR_GetFadeMask(lumpnum_t fademasklumpnum);
GLMapTexture_t *HWR_GetTexture(INT32 tex); GLMapTexture_t *HWR_GetTexture(INT32 tex, boolean chromakeyed);
void HWR_GetLevelFlat(levelflat_t *levelflat, boolean chromakeyed); void HWR_GetLevelFlat(levelflat_t *levelflat, boolean chromakeyed);
void HWR_GetRawFlat(lumpnum_t flatlumpnum); void HWR_GetRawFlat(lumpnum_t flatlumpnum);
@ -133,7 +133,8 @@ void HWR_UnlockCachedPatch(GLPatch_t *gpatch);
void HWR_SetPalette(RGBA_t *palette); void HWR_SetPalette(RGBA_t *palette);
void HWR_SetMapPalette(void); void HWR_SetMapPalette(void);
UINT32 HWR_CreateLightTable(UINT8 *lighttable); UINT32 HWR_CreateLightTable(UINT8 *lighttable, RGBA_t *hw_lighttable);
void HWR_UpdateLightTable(UINT32 id, UINT8 *lighttable, RGBA_t *hw_lighttable);
UINT32 HWR_GetLightTableID(extracolormap_t *colormap); UINT32 HWR_GetLightTableID(extracolormap_t *colormap);
void HWR_ClearLightTables(void); void HWR_ClearLightTables(void);

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -309,6 +309,43 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta)
return (FUINT)finallight; return (FUINT)finallight;
} }
static UINT8 HWR_SideLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light +
((side->lightabsolute) ? 0 : base_lightlevel)));
}
/* TODO: implement per-texture lighting
static UINT8 HWR_TopLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_top +
((side->lightabsolute_top) ? 0 : HWR_SideLightLevel(side, base_lightlevel))));
}
static UINT8 HWR_MidLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_mid +
((side->lightabsolute_mid) ? 0 : HWR_SideLightLevel(side, base_lightlevel))));
}
static UINT8 HWR_BottomLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_bottom +
((side->lightabsolute_bottom) ? 0 : HWR_SideLightLevel(side, base_lightlevel))));
}
*/
static UINT8 HWR_FloorLightLevel(sector_t *sector, INT16 base_lightlevel)
{
return max(0, min(255, sector->floorlightlevel +
((sector->floorlightabsolute) ? 0 : base_lightlevel)));
}
static UINT8 HWR_CeilingLightLevel(sector_t *sector, INT16 base_lightlevel)
{
return max(0, min(255, sector->ceilinglightlevel +
((sector->ceilinglightabsolute) ? 0 : base_lightlevel)));
}
// ========================================================================== // ==========================================================================
// FLOOR/CEILING GENERATION FROM SUBSECTORS // FLOOR/CEILING GENERATION FROM SUBSECTORS
// ========================================================================== // ==========================================================================
@ -705,8 +742,9 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
fixed_t v2x = FloatToFixed(wallVerts[1].x); fixed_t v2x = FloatToFixed(wallVerts[1].x);
fixed_t v2y = FloatToFixed(wallVerts[1].z); fixed_t v2y = FloatToFixed(wallVerts[1].z);
FUINT lightnum = HWR_SideLightLevel(gl_sidedef, sector->lightlevel);
const UINT8 alpha = Surf->PolyColor.s.alpha; const UINT8 alpha = Surf->PolyColor.s.alpha;
FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y); lightnum = HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y);
extracolormap_t *colormap = NULL; extracolormap_t *colormap = NULL;
if (!r_renderwalls) if (!r_renderwalls)
@ -750,13 +788,13 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum,
{ {
if (pfloor && (pfloor->fofflags & FOF_FOG)) if (pfloor && (pfloor->fofflags & FOF_FOG))
{ {
lightnum = pfloor->master->frontsector->lightlevel; lightnum = HWR_SideLightLevel(gl_sidedef, pfloor->master->frontsector->lightlevel);
colormap = pfloor->master->frontsector->extra_colormap; colormap = pfloor->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y);
} }
else else
{ {
lightnum = *list[i].lightlevel; lightnum = HWR_SideLightLevel(gl_sidedef, *list[i].lightlevel);
colormap = *list[i].extra_colormap; colormap = *list[i].extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y);
} }
@ -916,6 +954,7 @@ static boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf)
static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliphigh, fixed_t worldtop, fixed_t worldbottom, fixed_t worldhigh, fixed_t worldlow, fixed_t worldtopslope, fixed_t worldbottomslope, fixed_t worldhighslope, fixed_t worldlowslope, UINT32 lightnum, FOutVector *inWallVerts) static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliphigh, fixed_t worldtop, fixed_t worldbottom, fixed_t worldhigh, fixed_t worldlow, fixed_t worldtopslope, fixed_t worldbottomslope, fixed_t worldhighslope, fixed_t worldlowslope, UINT32 lightnum, FOutVector *inWallVerts)
{ {
sector_t *front, *back;
FOutVector wallVerts[4]; FOutVector wallVerts[4];
FSurfaceInfo Surf; FSurfaceInfo Surf;
@ -925,6 +964,16 @@ static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliph
if (!HWR_BlendMidtextureSurface(&Surf)) if (!HWR_BlendMidtextureSurface(&Surf))
return; return;
if (gl_linedef->frontsector->heightsec != -1)
front = &sectors[gl_linedef->frontsector->heightsec];
else
front = gl_linedef->frontsector;
if (gl_linedef->backsector->heightsec != -1)
back = &sectors[gl_linedef->backsector->heightsec];
else
back = gl_linedef->backsector;
fixed_t texheight = FixedDiv(textureheight[gl_midtexture], abs(gl_sidedef->scaley_mid)); fixed_t texheight = FixedDiv(textureheight[gl_midtexture], abs(gl_sidedef->scaley_mid));
INT32 repeats; INT32 repeats;
@ -934,15 +983,15 @@ static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliph
{ {
fixed_t high, low; fixed_t high, low;
if (gl_frontsector->ceilingheight > gl_backsector->ceilingheight) if (front->ceilingheight > back->ceilingheight)
high = gl_backsector->ceilingheight; high = back->ceilingheight;
else else
high = gl_frontsector->ceilingheight; high = front->ceilingheight;
if (gl_frontsector->floorheight > gl_backsector->floorheight) if (front->floorheight > back->floorheight)
low = gl_frontsector->floorheight; low = front->floorheight;
else else
low = gl_backsector->floorheight; low = back->floorheight;
repeats = (high - low) / texheight; repeats = (high - low) / texheight;
if ((high - low) % texheight) if ((high - low) % texheight)
@ -951,7 +1000,7 @@ static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliph
else else
repeats = 1; repeats = 1;
GLMapTexture_t *grTex = HWR_GetTexture(gl_midtexture); GLMapTexture_t *grTex = HWR_GetTexture(gl_midtexture, true);
float xscale = FixedToFloat(gl_sidedef->scalex_mid); float xscale = FixedToFloat(gl_sidedef->scalex_mid);
float yscale = FixedToFloat(gl_sidedef->scaley_mid); float yscale = FixedToFloat(gl_sidedef->scaley_mid);
@ -969,8 +1018,8 @@ static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliph
if (gl_curline->polyseg) if (gl_curline->polyseg)
{ {
// Change this when polyobjects support slopes // Change this when polyobjects support slopes
popentop = popentopslope = gl_curline->backsector->ceilingheight; popentop = popentopslope = back->ceilingheight;
popenbottom = popenbottomslope = gl_curline->backsector->floorheight; popenbottom = popenbottomslope = back->floorheight;
} }
else else
{ {
@ -1167,7 +1216,7 @@ static void HWR_ProcessSeg(void)
float cliplow = (float)gl_curline->offset; float cliplow = (float)gl_curline->offset;
float cliphigh = cliplow + (gl_curline->flength * FRACUNIT); float cliphigh = cliplow + (gl_curline->flength * FRACUNIT);
FUINT lightnum = gl_frontsector->lightlevel; FUINT lightnum = HWR_SideLightLevel(gl_sidedef, gl_frontsector->lightlevel);
extracolormap_t *colormap = gl_frontsector->extra_colormap; extracolormap_t *colormap = gl_frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
@ -1210,7 +1259,7 @@ static void HWR_ProcessSeg(void)
// check TOP TEXTURE // check TOP TEXTURE
if ((worldhighslope < worldtopslope || worldhigh < worldtop) && gl_toptexture) if ((worldhighslope < worldtopslope || worldhigh < worldtop) && gl_toptexture)
{ {
grTex = HWR_GetTexture(gl_toptexture); grTex = HWR_GetTexture(gl_toptexture, false);
xscale = FixedToFloat(abs(gl_sidedef->scalex_top)); xscale = FixedToFloat(abs(gl_sidedef->scalex_top));
yscale = FixedToFloat(abs(gl_sidedef->scaley_top)); yscale = FixedToFloat(abs(gl_sidedef->scaley_top));
@ -1300,7 +1349,7 @@ static void HWR_ProcessSeg(void)
// check BOTTOM TEXTURE // check BOTTOM TEXTURE
if ((worldlowslope > worldbottomslope || worldlow > worldbottom) && gl_bottomtexture) if ((worldlowslope > worldbottomslope || worldlow > worldbottom) && gl_bottomtexture)
{ {
grTex = HWR_GetTexture(gl_bottomtexture); grTex = HWR_GetTexture(gl_bottomtexture, false);
xscale = FixedToFloat(abs(gl_sidedef->scalex_bottom)); xscale = FixedToFloat(abs(gl_sidedef->scalex_bottom));
yscale = FixedToFloat(abs(gl_sidedef->scaley_bottom)); yscale = FixedToFloat(abs(gl_sidedef->scaley_bottom));
@ -1414,7 +1463,7 @@ static void HWR_ProcessSeg(void)
// Single sided line... Deal only with the middletexture (if one exists) // Single sided line... Deal only with the middletexture (if one exists)
if (gl_midtexture && gl_linedef->special != SPECIAL_HORIZON_LINE) // (Ignore horizon line for OGL) if (gl_midtexture && gl_linedef->special != SPECIAL_HORIZON_LINE) // (Ignore horizon line for OGL)
{ {
grTex = HWR_GetTexture(gl_midtexture); grTex = HWR_GetTexture(gl_midtexture, false);
xscale = FixedToFloat(gl_sidedef->scalex_mid); xscale = FixedToFloat(gl_sidedef->scalex_mid);
yscale = FixedToFloat(gl_sidedef->scaley_mid); yscale = FixedToFloat(gl_sidedef->scaley_mid);
@ -1588,7 +1637,7 @@ static void HWR_ProcessSeg(void)
// -- Monster Iestyn 26/06/18 // -- Monster Iestyn 26/06/18
fixed_t texturevpeg = side->rowoffset + side->offsety_mid; fixed_t texturevpeg = side->rowoffset + side->offsety_mid;
grTex = HWR_GetTexture(texnum); grTex = HWR_GetTexture(texnum, true);
xscale = FixedToFloat(side->scalex_mid); xscale = FixedToFloat(side->scalex_mid);
yscale = FixedToFloat(side->scaley_mid); yscale = FixedToFloat(side->scaley_mid);
@ -1628,11 +1677,11 @@ static void HWR_ProcessSeg(void)
{ {
blendmode = PF_Fog|PF_NoTexture; blendmode = PF_Fog|PF_NoTexture;
lightnum = rover->master->frontsector->lightlevel; lightnum = HWR_SideLightLevel(gl_sidedef, rover->master->frontsector->lightlevel);
colormap = rover->master->frontsector->extra_colormap; colormap = rover->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(HWR_SideLightLevel(gl_sidedef, rover->master->frontsector->lightlevel), rover->master->frontsector->extra_colormap);
if (gl_frontsector->numlights) if (gl_frontsector->numlights)
HWR_SplitWall(gl_frontsector, wallVerts, 0, &Surf, rover->fofflags, rover, blendmode); HWR_SplitWall(gl_frontsector, wallVerts, 0, &Surf, rover->fofflags, rover, blendmode);
@ -1643,7 +1692,7 @@ static void HWR_ProcessSeg(void)
{ {
blendmode = PF_Masked; blendmode = PF_Masked;
if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) if ((rover->fofflags & FOF_TRANSLUCENT && !((rover->fofflags & FOF_SPLAT) && rover->alpha >= 255)) || rover->blend)
{ {
blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent;
Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255)); Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255));
@ -1745,7 +1794,7 @@ static void HWR_ProcessSeg(void)
// -- Monster Iestyn 26/06/18 // -- Monster Iestyn 26/06/18
fixed_t texturevpeg = side->rowoffset + side->offsety_mid; fixed_t texturevpeg = side->rowoffset + side->offsety_mid;
grTex = HWR_GetTexture(texnum); grTex = HWR_GetTexture(texnum, true);
xscale = FixedToFloat(side->scalex_mid); xscale = FixedToFloat(side->scalex_mid);
yscale = FixedToFloat(side->scaley_mid); yscale = FixedToFloat(side->scaley_mid);
@ -1785,7 +1834,7 @@ static void HWR_ProcessSeg(void)
{ {
blendmode = PF_Fog|PF_NoTexture; blendmode = PF_Fog|PF_NoTexture;
lightnum = rover->master->frontsector->lightlevel; lightnum = HWR_SideLightLevel(gl_sidedef, rover->master->frontsector->lightlevel);
colormap = rover->master->frontsector->extra_colormap; colormap = rover->master->frontsector->extra_colormap;
lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y);
@ -1800,7 +1849,7 @@ static void HWR_ProcessSeg(void)
{ {
blendmode = PF_Masked; blendmode = PF_Masked;
if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) if ((rover->fofflags & FOF_TRANSLUCENT && !((rover->fofflags & FOF_SPLAT) && rover->alpha >= 255)) || rover->blend)
{ {
blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent;
Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255)); Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255));
@ -2442,7 +2491,7 @@ static void HWR_Subsector(size_t num)
rover; rover = rover->next) rover; rover = rover->next)
{ {
fixed_t bottomCullHeight, topCullHeight, centerHeight; fixed_t bottomCullHeight, topCullHeight, centerHeight;
if (!(rover->fofflags & FOF_EXISTS) || !(rover->fofflags & FOF_RENDERPLANES)) if (!(rover->fofflags & FOF_EXISTS) || !(rover->fofflags & FOF_RENDERPLANES))
continue; continue;
if (sub->validcount == validcount) if (sub->validcount == validcount)
@ -2454,7 +2503,7 @@ static void HWR_Subsector(size_t num)
if (gl_frontsector->cullheight) if (gl_frontsector->cullheight)
{ {
if (HWR_DoCulling(gl_frontsector->cullheight, viewsector->cullheight, gl_viewz, FIXED_TO_FLOAT(bottomCullHeight), FIXED_TO_FLOAT(topCullHeight))) if (HWR_DoCulling(gl_frontsector->cullheight, viewsector->cullheight, gl_viewz, FIXED_TO_FLOAT(*rover->bottomheight), FIXED_TO_FLOAT(*rover->topheight)))
continue; continue;
} }
@ -2471,17 +2520,17 @@ static void HWR_Subsector(size_t num)
UINT8 alpha; UINT8 alpha;
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false); light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap); alpha = HWR_FogBlockAlpha(HWR_FloorLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel), rover->master->frontsector->extra_colormap);
HWR_AddTransparentFloor(0, HWR_AddTransparentFloor(0,
&extrasubsectors[num], &extrasubsectors[num],
false, false,
*rover->bottomheight, *rover->bottomheight,
*gl_frontsector->lightlist[light].lightlevel, HWR_FloorLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
alpha, rover->master->frontsector, PF_Fog|PF_NoTexture, alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
true, false, rover->master->frontsector->extra_colormap); true, false, rover->master->frontsector->extra_colormap);
} }
else if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) // SoM: Flags are more efficient else if ((rover->fofflags & FOF_TRANSLUCENT && !((rover->fofflags & FOF_SPLAT) && rover->alpha >= 255)) || rover->blend) // SoM: Flags are more efficient
{ {
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false); light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
@ -2489,7 +2538,7 @@ static void HWR_Subsector(size_t num)
&extrasubsectors[num], &extrasubsectors[num],
false, false,
*rover->bottomheight, *rover->bottomheight,
*gl_frontsector->lightlist[light].lightlevel, HWR_FloorLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
max(0, min(rover->alpha, 255)), rover->master->frontsector, max(0, min(rover->alpha, 255)), rover->master->frontsector,
HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent), HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent),
false, rover->fofflags & FOF_SPLAT, *gl_frontsector->lightlist[light].extra_colormap); false, rover->fofflags & FOF_SPLAT, *gl_frontsector->lightlist[light].extra_colormap);
@ -2498,8 +2547,9 @@ static void HWR_Subsector(size_t num)
{ {
HWR_GetLevelFlat(&levelflats[*rover->bottompic], rover->fofflags & FOF_SPLAT); HWR_GetLevelFlat(&levelflats[*rover->bottompic], rover->fofflags & FOF_SPLAT);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false); light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < bottomCullHeight ? true : false);
HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic], HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude,
rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap); HWR_FloorLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
&levelflats[*rover->bottompic], rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
} }
} }
@ -2516,17 +2566,17 @@ static void HWR_Subsector(size_t num)
UINT8 alpha; UINT8 alpha;
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false); light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
alpha = HWR_FogBlockAlpha(*gl_frontsector->lightlist[light].lightlevel, rover->master->frontsector->extra_colormap); alpha = HWR_FogBlockAlpha(HWR_CeilingLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel), rover->master->frontsector->extra_colormap);
HWR_AddTransparentFloor(0, HWR_AddTransparentFloor(0,
&extrasubsectors[num], &extrasubsectors[num],
true, true,
*rover->topheight, *rover->topheight,
*gl_frontsector->lightlist[light].lightlevel, HWR_CeilingLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
alpha, rover->master->frontsector, PF_Fog|PF_NoTexture, alpha, rover->master->frontsector, PF_Fog|PF_NoTexture,
true, false, rover->master->frontsector->extra_colormap); true, false, rover->master->frontsector->extra_colormap);
} }
else if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) else if ((rover->fofflags & FOF_TRANSLUCENT && !((rover->fofflags & FOF_SPLAT) && rover->alpha >= 255)) || rover->blend)
{ {
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false); light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
@ -2534,7 +2584,7 @@ static void HWR_Subsector(size_t num)
&extrasubsectors[num], &extrasubsectors[num],
true, true,
*rover->topheight, *rover->topheight,
*gl_frontsector->lightlist[light].lightlevel, HWR_CeilingLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
max(0, min(rover->alpha, 255)), rover->master->frontsector, max(0, min(rover->alpha, 255)), rover->master->frontsector,
HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent), HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent),
false, rover->fofflags & FOF_SPLAT, *gl_frontsector->lightlist[light].extra_colormap); false, rover->fofflags & FOF_SPLAT, *gl_frontsector->lightlist[light].extra_colormap);
@ -2543,8 +2593,9 @@ static void HWR_Subsector(size_t num)
{ {
HWR_GetLevelFlat(&levelflats[*rover->toppic], rover->fofflags & FOF_SPLAT); HWR_GetLevelFlat(&levelflats[*rover->toppic], rover->fofflags & FOF_SPLAT);
light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false); light = R_GetPlaneLight(gl_frontsector, centerHeight, viewz < topCullHeight ? true : false);
HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic], HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude,
rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap); HWR_CeilingLightLevel(rover->master->frontsector, *gl_frontsector->lightlist[light].lightlevel),
&levelflats[*rover->toppic], rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap);
} }
} }
} }
@ -2880,7 +2931,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
} }
HWR_Lighting(&sSurf, 0, colormap); HWR_Lighting(&sSurf, 0, colormap);
sSurf.PolyColor.s.alpha = alpha; sSurf.PolyColor.s.alpha = FixedMul(thing->alpha, alpha);
if (HWR_UseShader()) if (HWR_UseShader())
{ {
@ -3054,11 +3105,16 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
// baseWallVerts is used to know the final shape to easily get the vertex // baseWallVerts is used to know the final shape to easily get the vertex
// co-ordinates // co-ordinates
memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts)); memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
fixed_t newalpha = spr->mobj->alpha;
// if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude) // if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude)
// this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw. // this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw.
if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer) if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
{
newalpha = spr->mobj->tracer->alpha;
occlusion = 0; occlusion = 0;
}
else else
occlusion = PF_Occlude; occlusion = PF_Occlude;
@ -3094,6 +3150,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
blend = HWR_GetBlendModeFlag(blendmode)|occlusion; blend = HWR_GetBlendModeFlag(blendmode)|occlusion;
if (!occlusion) use_linkdraw_hack = true; if (!occlusion) use_linkdraw_hack = true;
} }
Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
if (HWR_UseShader()) if (HWR_UseShader())
{ {
@ -3543,11 +3601,15 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
FBITFIELD blend = 0; FBITFIELD blend = 0;
FBITFIELD occlusion; FBITFIELD occlusion;
boolean use_linkdraw_hack = false; boolean use_linkdraw_hack = false;
fixed_t newalpha = spr->mobj->alpha;
// if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude) // if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude)
// this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw. // this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw.
if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer) if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
{
occlusion = 0; occlusion = 0;
newalpha = spr->mobj->tracer->alpha;
}
else else
occlusion = PF_Occlude; occlusion = PF_Occlude;
@ -3583,6 +3645,8 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
blend = HWR_GetBlendModeFlag(blendmode)|occlusion; blend = HWR_GetBlendModeFlag(blendmode)|occlusion;
if (!occlusion) use_linkdraw_hack = true; if (!occlusion) use_linkdraw_hack = true;
} }
Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
if (spr->renderflags & RF_SHADOWEFFECTS) if (spr->renderflags & RF_SHADOWEFFECTS)
{ {
@ -3893,7 +3957,7 @@ void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boo
planeinfo[numplanes].isceiling = isceiling; planeinfo[numplanes].isceiling = isceiling;
planeinfo[numplanes].fixedheight = fixedheight; planeinfo[numplanes].fixedheight = fixedheight;
planeinfo[numplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? 255 : lightlevel; planeinfo[numplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? lightlevel : 255; // TODO: 2.3: Make transparent FOF planes always use light level
planeinfo[numplanes].levelflat = levelflat; planeinfo[numplanes].levelflat = levelflat;
planeinfo[numplanes].xsub = xsub; planeinfo[numplanes].xsub = xsub;
planeinfo[numplanes].alpha = alpha; planeinfo[numplanes].alpha = alpha;
@ -3925,7 +3989,7 @@ void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polyse
polyplaneinfo[numpolyplanes].isceiling = isceiling; polyplaneinfo[numpolyplanes].isceiling = isceiling;
polyplaneinfo[numpolyplanes].fixedheight = fixedheight; polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
polyplaneinfo[numpolyplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? 255 : lightlevel; polyplaneinfo[numpolyplanes].lightlevel = (planecolormap && (planecolormap->flags & CMF_FOG)) ? lightlevel : 255; // TODO: 2.3: Make transparent polyobject planes always use light level
polyplaneinfo[numpolyplanes].levelflat = levelflat; polyplaneinfo[numpolyplanes].levelflat = levelflat;
polyplaneinfo[numpolyplanes].polysector = polysector; polyplaneinfo[numpolyplanes].polysector = polysector;
polyplaneinfo[numpolyplanes].alpha = alpha; polyplaneinfo[numpolyplanes].alpha = alpha;
@ -4086,7 +4150,7 @@ static void HWR_CreateDrawNodes(void)
else if (sortnode[sortindex[i]].wall) else if (sortnode[sortindex[i]].wall)
{ {
if (!(sortnode[sortindex[i]].wall->blend & PF_NoTexture)) if (!(sortnode[sortindex[i]].wall->blend & PF_NoTexture))
HWR_GetTexture(sortnode[sortindex[i]].wall->texnum); HWR_GetTexture(sortnode[sortindex[i]].wall->texnum, true);
HWR_RenderWall(sortnode[sortindex[i]].wall->wallVerts, &sortnode[sortindex[i]].wall->Surf, sortnode[sortindex[i]].wall->blend, sortnode[sortindex[i]].wall->fogwall, HWR_RenderWall(sortnode[sortindex[i]].wall->wallVerts, &sortnode[sortindex[i]].wall->Surf, sortnode[sortindex[i]].wall->blend, sortnode[sortindex[i]].wall->fogwall,
sortnode[sortindex[i]].wall->lightlevel, sortnode[sortindex[i]].wall->wallcolormap); sortnode[sortindex[i]].wall->lightlevel, sortnode[sortindex[i]].wall->wallcolormap);
} }
@ -5066,6 +5130,8 @@ static void HWR_DrawSkyBackground(player_t *player)
HWD.pfnSetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); HWD.pfnSetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated);
HWR_GetTexture(texturetranslation[skytexture], false);
if (cv_glskydome.value) if (cv_glskydome.value)
{ {
FTransform dometransform; FTransform dometransform;
@ -5081,8 +5147,6 @@ static void HWR_DrawSkyBackground(player_t *player)
HWR_SetTransformAiming(&dometransform, player, false); HWR_SetTransformAiming(&dometransform, player, false);
dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
HWR_GetTexture(texturetranslation[skytexture]);
if (gl_sky.texture != texturetranslation[skytexture]) if (gl_sky.texture != texturetranslation[skytexture])
{ {
HWR_ClearSkyDome(); HWR_ClearSkyDome();
@ -5102,7 +5166,6 @@ static void HWR_DrawSkyBackground(player_t *player)
float aspectratio; float aspectratio;
float angleturn; float angleturn;
HWR_GetTexture(texturetranslation[skytexture]);
aspectratio = (float)vid.width/(float)vid.height; aspectratio = (float)vid.width/(float)vid.height;
//Hurdler: the sky is the only texture who need 4.0f instead of 1.0 //Hurdler: the sky is the only texture who need 4.0f instead of 1.0
@ -5542,7 +5605,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
// Can't have palette rendering if shaders are disabled. // Can't have palette rendering if shaders are disabled.
boolean HWR_ShouldUsePaletteRendering(void) boolean HWR_ShouldUsePaletteRendering(void)
{ {
return (cv_glpaletterendering.value && HWR_UseShader()); return (pMasterPalette != NULL && cv_glpaletterendering.value && HWR_UseShader());
} }
// enable or disable palette rendering state depending on settings and availability // enable or disable palette rendering state depending on settings and availability
@ -5659,7 +5722,7 @@ consvar_t cv_glbatching = CVAR_INIT ("gr_batching", "On", 0, CV_OnOff, NULL);
static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 bits"}, {0, NULL}}; static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 bits"}, {0, NULL}};
consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletterendering", "Off", CV_SAVE|CV_CALL, CV_OnOff, CV_glpaletterendering_OnChange); consvar_t cv_glpaletterendering = CVAR_INIT ("gr_paletterendering", "On", CV_SAVE|CV_CALL, CV_OnOff, CV_glpaletterendering_OnChange);
consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange); consvar_t cv_glpalettedepth = CVAR_INIT ("gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_glpalettedepth_OnChange);
#define ONLY_IF_GL_LOADED if (vid.glstate != VID_GL_LIBRARY_LOADED) return; #define ONLY_IF_GL_LOADED if (vid.glstate != VID_GL_LIBRARY_LOADED) return;

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -1289,6 +1289,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
// Apparently people don't like jump frames like that, so back it goes // Apparently people don't like jump frames like that, so back it goes
//if (tics > durs) //if (tics > durs)
//durs = tics; //durs = tics;
// Make linkdraw objects use their tracer's alpha value
fixed_t newalpha = spr->mobj->alpha;
if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer)
newalpha = spr->mobj->tracer->alpha;
INT32 blendmode; INT32 blendmode;
if (spr->mobj->frame & FF_BLENDMASK) if (spr->mobj->frame & FF_BLENDMASK)
@ -1303,6 +1308,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
Surf.PolyColor.s.alpha = (spr->mobj->flags2 & MF2_SHADOW) ? 0x40 : 0xff; Surf.PolyColor.s.alpha = (spr->mobj->flags2 & MF2_SHADOW) ? 0x40 : 0xff;
Surf.PolyFlags = HWR_GetBlendModeFlag(blendmode); Surf.PolyFlags = HWR_GetBlendModeFlag(blendmode);
} }
Surf.PolyColor.s.alpha = FixedMul(newalpha, Surf.PolyColor.s.alpha);
// don't forget to enable the depth test because we can't do this // don't forget to enable the depth test because we can't do this
// like before: model polygons are not sorted // like before: model polygons are not sorted

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2021 by Sonic Team Junior. // Copyright (C) 2021-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -448,6 +448,101 @@ void HWR_LoadAllCustomShaders(void)
HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i])); HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i]));
} }
static const char version_directives[][14] = {
"#version 330\n",
"#version 150\n",
"#version 140\n",
"#version 130\n",
"#version 120\n",
"#version 110\n",
};
static boolean HWR_VersionDirectiveExists(const char* source)
{
return strncmp(source, "#version", 8) == 0;
}
static char* HWR_PrependVersionDirective(const char* source, UINT32 version_index)
{
const UINT32 version_len = sizeof(version_directives[version_index]) - 1;
const UINT32 source_len = strlen(source);
char* result = Z_Malloc(source_len + version_len + 1, PU_STATIC, NULL);
strcpy(result, version_directives[version_index]);
strcpy(result + version_len, source);
return result;
}
static void HWR_ReplaceVersionInplace(char* shader, UINT32 version_index)
{
shader[9] = version_directives[version_index][9];
shader[10] = version_directives[version_index][10];
shader[11] = version_directives[version_index][11];
}
static boolean HWR_CheckVersionDirectives(const char* vert, const char* frag)
{
return HWR_VersionDirectiveExists(vert) && HWR_VersionDirectiveExists(frag);
}
static void HWR_TryToCompileShaderWithImplicitVersion(INT32 shader_index, INT32 shaderxlat_id)
{
char* vert_shader = gl_shaders[shader_index].vertex;
char* frag_shader = gl_shaders[shader_index].fragment;
boolean vert_shader_version_exists = HWR_VersionDirectiveExists(vert_shader);
boolean frag_shader_version_exists = HWR_VersionDirectiveExists(frag_shader);
if(!vert_shader_version_exists) {
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: vertex shader '%s' is missing a #version directive\n", HWR_GetShaderName(shaderxlat_id));
}
if(!frag_shader_version_exists) {
CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: fragment shader '%s' is missing a #version directive\n", HWR_GetShaderName(shaderxlat_id));
}
// try to compile as is
HWR_CompileShader(shader_index);
if (gl_shaders[shader_index].compiled)
return;
// try each version directive
for(UINT32 i = 0; i < sizeof(version_directives) / sizeof(version_directives[0]); ++i) {
CONS_Alert(CONS_NOTICE, "HWR_TryToCompileShaderWithImplicitVersion: Trying %s\n", version_directives[i]);
if(!vert_shader_version_exists) {
// first time reallocation would have to be made
if(i == 0) {
void* old = (void*)gl_shaders[shader_index].vertex;
vert_shader = gl_shaders[shader_index].vertex = HWR_PrependVersionDirective(vert_shader, i);
Z_Free(old);
} else {
HWR_ReplaceVersionInplace(vert_shader, i);
}
}
if(!frag_shader_version_exists) {
if(i == 0) {
void* old = (void*)gl_shaders[shader_index].fragment;
frag_shader = gl_shaders[shader_index].fragment = HWR_PrependVersionDirective(frag_shader, i);
Z_Free(old);
} else {
HWR_ReplaceVersionInplace(frag_shader, i);
}
}
HWR_CompileShader(shader_index);
if (gl_shaders[shader_index].compiled) {
CONS_Alert(CONS_NOTICE, "HWR_TryToCompileShaderWithImplicitVersion: Compiled with %s\n",
version_directives[i]);
CONS_Alert(CONS_WARNING, "Implicit GLSL version is used. Correct behavior is not guaranteed\n");
return;
}
}
}
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3) void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3)
{ {
UINT16 lump; UINT16 lump;
@ -610,7 +705,13 @@ skip_field:
gl_shaders[shader_index].fragment = Z_StrDup(gl_shadersources[i].fragment); gl_shaders[shader_index].fragment = Z_StrDup(gl_shadersources[i].fragment);
if (!gl_shaders[shader_index].vertex) if (!gl_shaders[shader_index].vertex)
gl_shaders[shader_index].vertex = Z_StrDup(gl_shadersources[i].vertex); gl_shaders[shader_index].vertex = Z_StrDup(gl_shadersources[i].vertex);
HWR_CompileShader(shader_index);
if(!HWR_CheckVersionDirectives(gl_shaders[shader_index].vertex, gl_shaders[shader_index].fragment)) {
HWR_TryToCompileShaderWithImplicitVersion(shader_index, i);
} else {
HWR_CompileShader(shader_index);
}
if (!gl_shaders[shader_index].compiled) if (!gl_shaders[shader_index].compiled)
CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: A compilation error occured for the %s shader in file %s. See the console messages above for more information.\n", shaderxlat[i].type, wadfiles[wadnum]->filename); CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: A compilation error occured for the %s shader in file %s. See the console messages above for more information.\n", shaderxlat[i].type, wadfiles[wadnum]->filename);
} }

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2021 by Sonic Team Junior. // Copyright (C) 2021-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -117,7 +117,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
#define pwglDeleteContext wglDeleteContext; #define pwglDeleteContext wglDeleteContext;
#define pwglMakeCurrent wglMakeCurrent; #define pwglMakeCurrent wglMakeCurrent;
#else #else
static HMODULE OGL32, GLU32; static HMODULE OGL32;
typedef void *(WINAPI *PFNwglGetProcAddress) (const char *); typedef void *(WINAPI *PFNwglGetProcAddress) (const char *);
static PFNwglGetProcAddress pwglGetProcAddress; static PFNwglGetProcAddress pwglGetProcAddress;
typedef HGLRC (WINAPI *PFNwglCreateContext) (HDC hdc); typedef HGLRC (WINAPI *PFNwglCreateContext) (HDC hdc);
@ -132,13 +132,6 @@ static PFNwglMakeCurrent pwglMakeCurrent;
void *GetGLFunc(const char *proc) void *GetGLFunc(const char *proc)
{ {
void *func = NULL; void *func = NULL;
if (strncmp(proc, "glu", 3) == 0)
{
if (GLU32)
func = GetProcAddress(GLU32, proc);
else
return NULL;
}
if (pwglGetProcAddress) if (pwglGetProcAddress)
func = pwglGetProcAddress(proc); func = pwglGetProcAddress(proc);
if (!func) if (!func)
@ -155,8 +148,6 @@ boolean LoadGL(void)
if (!OGL32) if (!OGL32)
return 0; return 0;
GLU32 = LoadLibrary("GLU32.DLL");
pwglGetProcAddress = GetGLFunc("wglGetProcAddress"); pwglGetProcAddress = GetGLFunc("wglGetProcAddress");
pwglCreateContext = GetGLFunc("wglCreateContext"); pwglCreateContext = GetGLFunc("wglCreateContext");
pwglDeleteContext = GetGLFunc("wglDeleteContext"); pwglDeleteContext = GetGLFunc("wglDeleteContext");
@ -528,7 +519,6 @@ EXPORT void HWRAPI(Shutdown) (void)
ReleaseDC(hWnd, hDC); ReleaseDC(hWnd, hDC);
hDC = NULL; hDC = NULL;
} }
FreeLibrary(GLU32);
FreeLibrary(OGL32); FreeLibrary(OGL32);
GL_DBG_Printf ("HWRAPI Shutdown(DONE)\n"); GL_DBG_Printf ("HWRAPI Shutdown(DONE)\n");
} }

View file

@ -96,6 +96,7 @@ static GLint min_filter = GL_LINEAR;
static GLint mag_filter = GL_LINEAR; static GLint mag_filter = GL_LINEAR;
static GLint anisotropic_filter = 0; static GLint anisotropic_filter = 0;
static boolean model_lighting = false; static boolean model_lighting = false;
boolean supportMipMap = false;
const GLubyte *gl_version = NULL; const GLubyte *gl_version = NULL;
const GLubyte *gl_renderer = NULL; const GLubyte *gl_renderer = NULL;
@ -417,9 +418,6 @@ static PFNglCopyTexImage2D pglCopyTexImage2D;
typedef void (APIENTRY * PFNglCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRY * PFNglCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
static PFNglCopyTexSubImage2D pglCopyTexSubImage2D; static PFNglCopyTexSubImage2D pglCopyTexSubImage2D;
#endif #endif
/* GLU functions */
typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
/* 1.2 functions for 3D textures */ /* 1.2 functions for 3D textures */
typedef void (APIENTRY * PFNglTexImage3D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRY * PFNglTexImage3D) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
@ -708,9 +706,6 @@ void SetupGLFunc4(void)
pglUniform3fv = GetGLFunc("glUniform3fv"); pglUniform3fv = GetGLFunc("glUniform3fv");
pglGetUniformLocation = GetGLFunc("glGetUniformLocation"); pglGetUniformLocation = GetGLFunc("glGetUniformLocation");
#endif #endif
// GLU
pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps");
} }
EXPORT boolean HWRAPI(InitShaders) (void) EXPORT boolean HWRAPI(InitShaders) (void)
@ -1617,7 +1612,8 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
//pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); //pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
if (MipMap) if (MipMap)
{ {
pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
if (pTexInfo->flags & TF_TRANSPARENT) if (pTexInfo->flags & TF_TRANSPARENT)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
@ -1638,7 +1634,8 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
//pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); //pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
if (MipMap) if (MipMap)
{ {
pgluBuild2DMipmaps(GL_TEXTURE_2D, GL_ALPHA, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0);
if (pTexInfo->flags & TF_TRANSPARENT) if (pTexInfo->flags & TF_TRANSPARENT)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 0); // No mippmaps on transparent stuff
@ -1658,7 +1655,8 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
{ {
if (MipMap) if (MipMap)
{ {
pgluBuild2DMipmaps(GL_TEXTURE_2D, textureformatGL, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
pglTexImage2D(GL_TEXTURE_2D, 0, textureformatGL, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
// Control the mipmap level of detail // Control the mipmap level of detail
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); // the lower the number, the higer the detail pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0); // the lower the number, the higer the detail
if (pTexInfo->flags & TF_TRANSPARENT) if (pTexInfo->flags & TF_TRANSPARENT)
@ -2241,7 +2239,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
mag_filter = GL_LINEAR; mag_filter = GL_LINEAR;
min_filter = GL_NEAREST; min_filter = GL_NEAREST;
} }
if (!pgluBuild2DMipmaps) if (!supportMipMap)
{ {
MipMap = GL_FALSE; MipMap = GL_FALSE;
min_filter = GL_LINEAR; min_filter = GL_LINEAR;
@ -3257,6 +3255,24 @@ EXPORT UINT32 HWRAPI(CreateLightTable)(RGBA_t *hw_lighttable)
return item->id; return item->id;
} }
EXPORT void HWRAPI(UpdateLightTable)(UINT32 id, RGBA_t *hw_lighttable)
{
LTListItem *item = LightTablesHead;
while (item && item->id != id)
item = item->next;
if (item)
{
pglBindTexture(GL_TEXTURE_2D, item->id);
// Just update it
pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 32, GL_RGBA, GL_UNSIGNED_BYTE, hw_lighttable);
// restore previously bound texture
pglBindTexture(GL_TEXTURE_2D, tex_downloaded);
}
}
// Delete light table textures, ids given before become invalid and must not be used. // Delete light table textures, ids given before become invalid and must not be used.
EXPORT void HWRAPI(ClearLightTables)(void) EXPORT void HWRAPI(ClearLightTables)(void)
{ {

View file

@ -35,7 +35,6 @@
#else #else
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glu.h>
#ifdef STATIC_OPENGL // Because of the 1.3 functions, you'll need GLext to compile it if static #ifdef STATIC_OPENGL // Because of the 1.3 functions, you'll need GLext to compile it if static
#define GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES
@ -127,6 +126,7 @@ extern GLint screen_width;
extern GLint screen_height; extern GLint screen_height;
extern GLbyte screen_depth; extern GLbyte screen_depth;
extern GLint maximumAnisotropy; extern GLint maximumAnisotropy;
extern boolean supportMipMap;
/** \brief OpenGL flags for video driver /** \brief OpenGL flags for video driver
*/ */

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -29,7 +29,7 @@
#include "i_video.h" #include "i_video.h"
#include "i_system.h" #include "i_system.h"
#include "st_stuff.h" // ST_HEIGHT #include "st_stuff.h"
#include "r_local.h" #include "r_local.h"
#include "keys.h" #include "keys.h"
@ -204,7 +204,7 @@ void HU_LoadGraphics(void)
HU_SetFontProperties(&hu_font, 0, 4, 8, 12); HU_SetFontProperties(&hu_font, 0, 4, 8, 12);
HU_SetFontProperties(&tny_font, 0, 2, 4, 12); HU_SetFontProperties(&tny_font, 0, 2, 4, 12);
HU_SetFontProperties(&cred_font, 0, 16, 16, 16); HU_SetFontProperties(&cred_font, 0, 16, 16, 16);
HU_SetFontProperties(&lt_font, 0, 16, 20, 20); HU_SetFontProperties(&lt_font, 0, 16, 20, 16);
HU_SetFontProperties(&ntb_font, 2, 4, 20, 21); HU_SetFontProperties(&ntb_font, 2, 4, 20, 21);
HU_SetFontProperties(&nto_font, 0, 4, 20, 21); HU_SetFontProperties(&nto_font, 0, 4, 20, 21);
@ -587,8 +587,8 @@ static void Command_CSay_f(void)
DoSayCommand(0, 1, HU_CSAY); DoSayCommand(0, 1, HU_CSAY);
} }
static tic_t spam_tokens[MAXPLAYERS] = { 1 }; // fill the buffer with 1 so the motd can be sent. UINT8 spam_tokens[MAXPLAYERS] = { 1 }; // fill the buffer with 1 so the motd can be sent.
static tic_t spam_tics[MAXPLAYERS]; tic_t spam_tics[MAXPLAYERS];
/** Receives a message, processing an ::XD_SAY command. /** Receives a message, processing an ::XD_SAY command.
* \sa DoSayCommand * \sa DoSayCommand
@ -649,14 +649,12 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
else else
spam_tokens[playernum] -= 1; spam_tokens[playernum] -= 1;
// run the lua hook even if we were supposed to eat the msg, netgame consistency goes first. if (spam_eatmsg)
return; // don't proceed if we were supposed to eat the message.
if (LUA_HookPlayerMsg(playernum, target, flags, msg)) if (LUA_HookPlayerMsg(playernum, target, flags, msg))
return; return;
if (spam_eatmsg)
return; // don't proceed if we were supposed to eat the message.
// If it's a CSAY, just CECHO and be done with it. // If it's a CSAY, just CECHO and be done with it.
if (flags & HU_CSAY) if (flags & HU_CSAY)
{ {
@ -1218,27 +1216,36 @@ static void HU_drawMiniChat(void)
INT32 charwidth = 4, charheight = 6; INT32 charwidth = 4, charheight = 6;
INT32 boxw = cv_chatwidth.value; INT32 boxw = cv_chatwidth.value;
INT32 dx = 0, dy = 0; INT32 dx = 0, dy = 0;
boolean prev_linereturn = false;
if (!chat_nummsg_min) if (!chat_nummsg_min)
return; // needless to say it's useless to do anything if we don't have anything to draw. return; // needless to say it's useless to do anything if we don't have anything to draw.
for (size_t i = chat_nummsg_min; i > 0; i--) for (size_t i = chat_nummsg_min; i > 0; i--)
{ {
char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]); char *msg = V_ChatWordWrap(0, boxw-charwidth-2, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE|V_MONOSPACE, chat_mini[i-1]);
for(size_t j = 0; msg[j]; j++) // iterate through msg for(size_t j = 0; msg[j]; j++) // iterate through msg
{ {
if (msg[j] == '\n') // get back down. if (msg[j] == '\n') // get back down.
{ {
chatheight += charheight; if (!prev_linereturn)
dx = 0; {
chatheight += charheight;
dx = 0;
}
prev_linereturn = true;
} }
else if (msg[j] >= FONTSTART) else if (msg[j] >= FONTSTART)
{ {
prev_linereturn = false;
dx += charwidth; dx += charwidth;
if (dx >= boxw)
if (dx >= boxw-charwidth-2)
{ {
dx = 0; dx = 0;
chatheight += charheight; chatheight += charheight;
prev_linereturn = true;
} }
} }
} }
@ -1250,35 +1257,43 @@ static void HU_drawMiniChat(void)
} }
y = chaty - (chatheight + charheight); y = chaty - (chatheight + charheight);
prev_linereturn = false;
for (size_t i = 0; i < chat_nummsg_min; i++) // iterate through our hot messages for (size_t i = 0; i < chat_nummsg_min; i++) // iterate through our hot messages
{ {
INT32 timer = ((cv_chattime.value*TICRATE)-chat_timers[i]) - cv_chattime.value*TICRATE+9; // see below... INT32 timer = ((cv_chattime.value*TICRATE)-chat_timers[i]) - cv_chattime.value*TICRATE+9; // see below...
INT32 transflag = (timer >= 0 && timer <= 9) ? (timer*V_10TRANS) : 0; // you can make bad jokes out of this one. INT32 transflag = (timer >= 0 && timer <= 9) ? (timer*V_10TRANS) : 0; // you can make bad jokes out of this one.
char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it. char *msg = V_ChatWordWrap(0, boxw-charwidth-2, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE|V_MONOSPACE, chat_mini[i]); // get the current message, and word wrap it.
UINT8 *colormap = NULL; UINT8 *colormap = NULL;
for(size_t j = 0; msg[j]; j++) // iterate through msg for(size_t j = 0; msg[j]; j++) // iterate through msg
{ {
if (msg[j] == '\n') // get back down. if (msg[j] == '\n') // get back down.
{ {
dy += charheight; if (!prev_linereturn)
dx = 0; {
dy += charheight;
dx = 0;
}
prev_linereturn = true;
} }
else if (msg[j] & 0x80) // get colormap else if (msg[j] & 0x80) // get colormap
colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK); colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK);
else if (msg[j] >= FONTSTART) else if (msg[j] >= FONTSTART)
{ {
prev_linereturn = false;
if (cv_chatbacktint.value) // on request of wolfy if (cv_chatbacktint.value) // on request of wolfy
V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT); V_DrawFillConsoleMap(x + dx + 2, y+dy, charwidth, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT);
V_DrawChatCharacter(x + dx + 2, y+dy, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag, true, colormap); V_DrawChatCharacter(x + dx + 2, y+dy, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_MONOSPACE|transflag, true, colormap);
dx += charwidth; dx += charwidth;
if (dx >= boxw)
if (dx >= boxw-charwidth-2)
{ {
dx = 0; dx = 0;
dy += charheight; dy += charheight;
prev_linereturn = true;
} }
} }
} }
@ -1303,6 +1318,7 @@ static void HU_drawChatLog(INT32 offset)
UINT32 i = 0; UINT32 i = 0;
INT32 chat_topy, chat_bottomy; INT32 chat_topy, chat_bottomy;
boolean atbottom = false; boolean atbottom = false;
boolean prev_linereturn = false;
// make sure that our scroll position isn't "illegal"; // make sure that our scroll position isn't "illegal";
if (chat_scroll > chat_maxscroll) if (chat_scroll > chat_maxscroll)
@ -1335,27 +1351,38 @@ static void HU_drawChatLog(INT32 offset)
for (i=0; i<chat_nummsg_log; i++) // iterate through our chatlog for (i=0; i<chat_nummsg_log; i++) // iterate through our chatlog
{ {
char *msg = V_ChatWordWrap(chatx, boxw-charwidth, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it. char *msg = V_ChatWordWrap(0, boxw-charwidth-2, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE|V_MONOSPACE, chat_log[i]); // get the current message, and word wrap it.
UINT8 *colormap = NULL; UINT8 *colormap = NULL;
for(size_t j = 0; msg[j]; j++) // iterate through msg for(size_t j = 0; msg[j]; j++) // iterate through msg
{ {
if (msg[j] == '\n') // get back down. if (msg[j] == '\n') // get back down.
{ {
dy += charheight; if (!prev_linereturn)
dx = 0; {
dy += charheight;
dx = 0;
}
prev_linereturn = true;
} }
else if (msg[j] & 0x80) // get colormap else if (msg[j] & 0x80) // get colormap
colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK); colormap = V_GetStringColormap(((msg[j] & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK);
else if (msg[j] >= FONTSTART) else
{ {
if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy))) prev_linereturn = false;
V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT, true, colormap);
dx += charwidth; if (msg[j] >= FONTSTART)
if (dx >= boxw-charwidth-2 && i<chat_nummsg_log) // end of message shouldn't count, nor should invisible characters!!!! {
if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy)))
V_DrawChatCharacter(x + dx + 2, y+dy+2, msg[j] |V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_MONOSPACE, true, colormap);
dx += charwidth;
}
if (dx >= boxw-charwidth-2 && i < chat_nummsg_log) // end of message shouldn't count, nor should invisible characters!!!!
{ {
dx = 0; dx = 0;
dy += charheight; dy += charheight;
prev_linereturn = true;
} }
} }
} }

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -79,6 +79,9 @@ void HU_AddChatText(const char *text, boolean playsound);
// set true when entering a chat message // set true when entering a chat message
extern boolean chat_on; extern boolean chat_on;
extern UINT8 spam_tokens[MAXPLAYERS];
extern tic_t spam_tics[MAXPLAYERS];
extern patch_t *emeraldpics[3][8]; extern patch_t *emeraldpics[3][8];
extern patch_t *rflagico; extern patch_t *rflagico;
extern patch_t *bflagico; extern patch_t *bflagico;

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -1784,8 +1784,8 @@ state_t states[NUMSTATES] =
{SPR_RING, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_RING, 0}, // S_RING {SPR_RING, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_RING, 0}, // S_RING
// Blue Sphere for special stages // Blue Sphere for special stages
{SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUESPHERE {SPR_SPHR, FF_SEMIBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_BLUESPHERE
{SPR_SPHR, FF_FULLBRIGHT {SPR_SPHR, FF_SEMIBRIGHT
#ifdef MANIASPHERES #ifdef MANIASPHERES
|FF_ANIMATE|FF_RANDOMANIM |FF_ANIMATE|FF_RANDOMANIM
#endif #endif
@ -1794,13 +1794,13 @@ state_t states[NUMSTATES] =
// Bomb Sphere // Bomb Sphere
{SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2, 0}, // S_BOMBSPHERE1 {SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2, 0}, // S_BOMBSPHERE1
{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3, 0}, // S_BOMBSPHERE2 {SPR_SPHR, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3, 0}, // S_BOMBSPHERE2
{SPR_SPHR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4, 0}, // S_BOMBSPHERE3 {SPR_SPHR, FF_SEMIBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4, 0}, // S_BOMBSPHERE3
{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1, 0}, // S_BOMBSPHERE4 {SPR_SPHR, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1, 0}, // S_BOMBSPHERE4
// NiGHTS Chip // NiGHTS Chip
{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 15, 2, S_NULL, 0}, // S_NIGHTSCHIP {SPR_NCHP, FF_SEMIBRIGHT|FF_ANIMATE, -1, {NULL}, 15, 2, S_NULL, 0}, // S_NIGHTSCHIP
{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE|16, -1, {NULL}, 15, 2, S_NULL, 0}, // S_NIGHTSCHIPBONUS {SPR_NCHP, FF_SEMIBRIGHT|FF_ANIMATE|16, -1, {NULL}, 15, 2, S_NULL, 0}, // S_NIGHTSCHIPBONUS
// NiGHTS Star // NiGHTS Star
{SPR_NSTR, FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL, 0}, // S_NIGHTSSTAR {SPR_NSTR, FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL, 0}, // S_NIGHTSSTAR
@ -1858,9 +1858,9 @@ state_t states[NUMSTATES] =
{SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG7 {SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL, 0}, // S_CEMG7
// Emerald hunt shards // Emerald hunt shards
{SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD1 {SPR_SHRD, FF_SEMIBRIGHT, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD1
{SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD2 {SPR_SHRD, FF_SEMIBRIGHT|1, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD2
{SPR_SHRD, 2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD3 {SPR_SHRD, FF_SEMIBRIGHT|2, -1, {NULL}, 0, 0, S_NULL, 0}, // S_SHRD3
// Bubble Source // Bubble Source
{SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2, 0}, // S_BUBBLES1 {SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2, 0}, // S_BUBBLES1

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -3181,17 +3181,25 @@ static int lib_rTextureNumForName(lua_State *L)
static int lib_rCheckTextureNameForNum(lua_State *L) static int lib_rCheckTextureNameForNum(lua_State *L)
{ {
char s[9];
INT32 num = (INT32)luaL_checkinteger(L, 1); INT32 num = (INT32)luaL_checkinteger(L, 1);
//HUDSAFE //HUDSAFE
lua_pushstring(L, R_CheckTextureNameForNum(num));
M_Memcpy(s, R_CheckTextureNameForNum(num), 8);
s[8] = '\0';
lua_pushstring(L, s);
return 1; return 1;
} }
static int lib_rTextureNameForNum(lua_State *L) static int lib_rTextureNameForNum(lua_State *L)
{ {
char s[9];
INT32 num = (INT32)luaL_checkinteger(L, 1); INT32 num = (INT32)luaL_checkinteger(L, 1);
//HUDSAFE //HUDSAFE
lua_pushstring(L, R_TextureNameForNum(num));
M_Memcpy(s, R_TextureNameForNum(num), 8);
s[8] = '\0';
lua_pushstring(L, s);
return 1; return 1;
} }
@ -3878,7 +3886,7 @@ static int lib_gAddPlayer(lua_State *L)
player_t *newplayer; player_t *newplayer;
SINT8 skinnum = 0, bot; SINT8 skinnum = 0, bot;
for (i = 0; i < MAXPLAYERS; i++) for (i = 1; i < MAXPLAYERS; i++)
{ {
if (!playeringame[i]) if (!playeringame[i])
break; break;

View file

@ -254,11 +254,10 @@ static int lib_searchBlockmap(lua_State *L)
} }
else // mobj and function only - search around mobj's radius by default else // mobj and function only - search around mobj's radius by default
{ {
fixed_t radius = mobj->radius + MAXRADIUS; x1 = mobj->x - mobj->radius;
x1 = mobj->x - radius; x2 = mobj->x + mobj->radius;
x2 = mobj->x + radius; y1 = mobj->y - mobj->radius;
y1 = mobj->y - radius; y2 = mobj->y + mobj->radius;
y2 = mobj->y + radius;
} }
lua_settop(L, 2); // pop everything except function, mobj lua_settop(L, 2); // pop everything except function, mobj

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2021-2022 by "Lactozilla". // Copyright (C) 2021-2024 by Lactozilla.
// Copyright (C) 2014-2023 by Sonic Team Junior. // Copyright (C) 2014-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -593,7 +593,7 @@ static int extracolormap_set(lua_State *L)
|| exc->fadergba != old_fade_rgba || exc->fadergba != old_fade_rgba
|| exc->fadestart != old_fade_start || exc->fadestart != old_fade_start
|| exc->fadeend != old_fade_end) || exc->fadeend != old_fade_end)
R_GenerateLightTable(exc, true); R_UpdateLightTable(exc, true);
return 0; return 0;
} }

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -72,6 +72,7 @@ automatically.
X (MusicChange),\ X (MusicChange),\
X (PlayerHeight),/* override player height */\ X (PlayerHeight),/* override player height */\
X (PlayerCanEnterSpinGaps),\ X (PlayerCanEnterSpinGaps),\
X (AddonLoaded),\
X (KeyDown),\ X (KeyDown),\
X (KeyUp),\ X (KeyUp),\

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -498,7 +498,25 @@ static int call_string_hooks(Hook_State *hook)
static int call_mobj_type_hooks(Hook_State *hook, mobjtype_t mobj_type) static int call_mobj_type_hooks(Hook_State *hook, mobjtype_t mobj_type)
{ {
return call_mapped(hook, &mobjHookIds[mobj_type][hook->hook_type]); int numCalls = call_mapped(hook, &mobjHookIds[mobj_type][hook->hook_type]);
if (numCalls > 0 && mobj_type == MT_NULL && (
hook->hook_type == MOBJ_HOOK(MobjThinker )
|| hook->hook_type == MOBJ_HOOK(MobjCollide )
|| hook->hook_type == MOBJ_HOOK(MobjLineCollide)
|| hook->hook_type == MOBJ_HOOK(MobjMoveCollide)
|| hook->hook_type == MOBJ_HOOK(MobjFuse )
|| hook->hook_type == MOBJ_HOOK(MobjThinker )
|| hook->hook_type == MOBJ_HOOK(BossThinker )
|| hook->hook_type == MOBJ_HOOK(MobjMoveBlocked)
|| hook->hook_type == MOBJ_HOOK(FollowMobj )
))
LUA_UsageWarning(L, va(
"%s hooks not attached to a specific mobj type are deprecated and will be removed.",
mobjHookNames[hook->hook_type])
);
return numCalls;
} }
static void call_hud_hooks static void call_hud_hooks
@ -751,7 +769,7 @@ static void hook_think_frame(int type)
PS_SetThinkFrameHookInfo(hook_index, time_taken, ar.short_src); PS_SetThinkFrameHookInfo(hook_index, time_taken, ar.short_src);
else if (type == 6) else if (type == 6)
PS_SetPostThinkFrameHookInfo(hook_index, time_taken, ar.short_src); PS_SetPostThinkFrameHookInfo(hook_index, time_taken, ar.short_src);
hook_index++; hook_index++;
} }
} }

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2014-2016 by John "JTE" Muniz. // Copyright (C) 2014-2016 by John "JTE" Muniz.
// Copyright (C) 2014-2023 by Sonic Team Junior. // Copyright (C) 2014-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2014-2016 by John "JTE" Muniz. // Copyright (C) 2014-2016 by John "JTE" Muniz.
// Copyright (C) 2014-2023 by Sonic Team Junior. // Copyright (C) 2014-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2014-2016 by John "JTE" Muniz. // Copyright (C) 2014-2016 by John "JTE" Muniz.
// Copyright (C) 2014-2023 by Sonic Team Junior. // Copyright (C) 2014-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -213,6 +213,14 @@ enum side_e {
side_sector, side_sector,
side_special, side_special,
side_repeatcnt, side_repeatcnt,
side_light,
side_light_top,
side_light_mid,
side_light_bottom,
side_lightabsolute,
side_lightabsolute_top,
side_lightabsolute_mid,
side_lightabsolute_bottom,
side_text side_text
}; };
@ -241,6 +249,14 @@ static const char *const side_opt[] = {
"sector", "sector",
"special", "special",
"repeatcnt", "repeatcnt",
"light",
"light_top",
"light_mid",
"light_bottom",
"lightabsolute",
"lightabsolute_top",
"lightabsolute_mid",
"lightabsolute_bottom",
"text", "text",
NULL}; NULL};
@ -1311,6 +1327,30 @@ static int side_get(lua_State *L)
case side_repeatcnt: case side_repeatcnt:
lua_pushinteger(L, side->repeatcnt); lua_pushinteger(L, side->repeatcnt);
return 1; return 1;
case side_light:
lua_pushinteger(L, side->light);
return 1;
case side_light_top:
lua_pushinteger(L, side->light_top);
return 1;
case side_light_mid:
lua_pushinteger(L, side->light_mid);
return 1;
case side_light_bottom:
lua_pushinteger(L, side->light_bottom);
return 1;
case side_lightabsolute:
lua_pushboolean(L, side->lightabsolute);
return 1;
case side_lightabsolute_top:
lua_pushboolean(L, side->lightabsolute_top);
return 1;
case side_lightabsolute_mid:
lua_pushboolean(L, side->lightabsolute_mid);
return 1;
case side_lightabsolute_bottom:
lua_pushboolean(L, side->lightabsolute_bottom);
return 1;
// TODO: 2.3: Delete // TODO: 2.3: Delete
case side_text: case side_text:
{ {
@ -1413,6 +1453,30 @@ static int side_set(lua_State *L)
case side_repeatcnt: case side_repeatcnt:
side->repeatcnt = luaL_checkinteger(L, 3); side->repeatcnt = luaL_checkinteger(L, 3);
break; break;
case side_light:
side->light = luaL_checkinteger(L, 3);
break;
case side_light_top:
side->light_top = luaL_checkinteger(L, 3);
break;
case side_light_mid:
side->light_mid = luaL_checkinteger(L, 3);
break;
case side_light_bottom:
side->light_bottom = luaL_checkinteger(L, 3);
break;
case side_lightabsolute:
side->lightabsolute = luaL_checkboolean(L, 3);
break;
case side_lightabsolute_top:
side->lightabsolute_top = luaL_checkboolean(L, 3);
break;
case side_lightabsolute_mid:
side->lightabsolute_mid = luaL_checkboolean(L, 3);
break;
case side_lightabsolute_bottom:
side->lightabsolute_bottom = luaL_checkboolean(L, 3);
break;
} }
return 0; return 0;
} }

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -69,6 +69,7 @@ enum mobj_e {
mobj_color, mobj_color,
mobj_translation, mobj_translation,
mobj_blendmode, mobj_blendmode,
mobj_alpha,
mobj_bnext, mobj_bnext,
mobj_bprev, mobj_bprev,
mobj_hnext, mobj_hnext,
@ -150,6 +151,7 @@ static const char *const mobj_opt[] = {
"color", "color",
"translation", "translation",
"blendmode", "blendmode",
"alpha",
"bnext", "bnext",
"bprev", "bprev",
"hnext", "hnext",
@ -196,12 +198,12 @@ static int mobj_get(lua_State *L)
enum mobj_e field = Lua_optoption(L, 2, -1, mobj_fields_ref); enum mobj_e field = Lua_optoption(L, 2, -1, mobj_fields_ref);
lua_settop(L, 2); lua_settop(L, 2);
if (!mo || !ISINLEVEL) { if (P_MobjWasRemoved(mo) || !ISINLEVEL) {
if (field == mobj_valid) { if (field == mobj_valid) {
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
return 1; return 1;
} }
if (!mo) { if (P_MobjWasRemoved(mo)) {
return LUA_ErrInvalid(L, "mobj_t"); return LUA_ErrInvalid(L, "mobj_t");
} else } else
return luaL_error(L, "Do not access an mobj_t field outside a level!"); return luaL_error(L, "Do not access an mobj_t field outside a level!");
@ -354,6 +356,9 @@ static int mobj_get(lua_State *L)
case mobj_blendmode: case mobj_blendmode:
lua_pushinteger(L, mo->blendmode); lua_pushinteger(L, mo->blendmode);
break; break;
case mobj_alpha:
lua_pushfixed(L, mo->alpha);
break;
case mobj_bnext: case mobj_bnext:
if (mo->blocknode && mo->blocknode->bnext) { if (mo->blocknode && mo->blocknode->bnext) {
LUA_PushUserdata(L, mo->blocknode->bnext->mobj, META_MOBJ); LUA_PushUserdata(L, mo->blocknode->bnext->mobj, META_MOBJ);
@ -733,6 +738,16 @@ static int mobj_set(lua_State *L)
mo->blendmode = blendmode; mo->blendmode = blendmode;
break; break;
} }
case mobj_alpha:
{
fixed_t alpha = luaL_checkfixed(L, 3);
if (alpha < 0)
alpha = 0;
else if (alpha > FRACUNIT)
alpha = FRACUNIT;
mo->alpha = alpha;
break;
}
case mobj_bnext: case mobj_bnext:
return NOSETPOS; return NOSETPOS;
case mobj_bprev: case mobj_bprev:

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -1098,7 +1098,7 @@ static UINT8 GetUserdataArchType(int index)
return ARCH_NULL; return ARCH_NULL;
} }
static UINT8 ArchiveValue(int TABLESINDEX, int myindex) static UINT8 ArchiveValue(save_t *save_p, int TABLESINDEX, int myindex)
{ {
if (myindex < 0) if (myindex < 0)
myindex = lua_gettop(gL)+1+myindex; myindex = lua_gettop(gL)+1+myindex;
@ -1106,34 +1106,34 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
case LUA_TNONE: case LUA_TNONE:
case LUA_TNIL: case LUA_TNIL:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
break; break;
// This might be a problem. D: // This might be a problem. D:
case LUA_TLIGHTUSERDATA: case LUA_TLIGHTUSERDATA:
case LUA_TTHREAD: case LUA_TTHREAD:
case LUA_TFUNCTION: case LUA_TFUNCTION:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 2; return 2;
case LUA_TBOOLEAN: case LUA_TBOOLEAN:
WRITEUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE); P_WriteUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE);
break; break;
case LUA_TNUMBER: case LUA_TNUMBER:
{ {
lua_Integer number = lua_tointeger(gL, myindex); lua_Integer number = lua_tointeger(gL, myindex);
if (number >= INT8_MIN && number <= INT8_MAX) if (number >= INT8_MIN && number <= INT8_MAX)
{ {
WRITEUINT8(save_p, ARCH_INT8); P_WriteUINT8(save_p, ARCH_INT8);
WRITESINT8(save_p, number); P_WriteSINT8(save_p, number);
} }
else if (number >= INT16_MIN && number <= INT16_MAX) else if (number >= INT16_MIN && number <= INT16_MAX)
{ {
WRITEUINT8(save_p, ARCH_INT16); P_WriteUINT8(save_p, ARCH_INT16);
WRITEINT16(save_p, number); P_WriteINT16(save_p, number);
} }
else else
{ {
WRITEUINT8(save_p, ARCH_INT32); P_WriteUINT8(save_p, ARCH_INT32);
WRITEFIXED(save_p, number); P_WriteFixed(save_p, number);
} }
break; break;
} }
@ -1144,23 +1144,23 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
UINT32 i = 0; UINT32 i = 0;
// if you're wondering why we're writing a string to save_p this way, // if you're wondering why we're writing a string to save_p this way,
// it turns out that Lua can have embedded zeros ('\0') in the strings, // it turns out that Lua can have embedded zeros ('\0') in the strings,
// so we can't use WRITESTRING as that cuts off when it finds a '\0'. // so we can't use P_WriteString as that cuts off when it finds a '\0'.
// Saving the size of the string also allows us to get the size of the string on the other end, // Saving the size of the string also allows us to get the size of the string on the other end,
// fixing the awful crashes previously encountered for reading strings longer than 1024 // fixing the awful crashes previously encountered for reading strings longer than 1024
// (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?) // (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?)
// -- Monster Iestyn 05/08/18 // -- Monster Iestyn 05/08/18
if (len < 255) if (len < 255)
{ {
WRITEUINT8(save_p, ARCH_SMALLSTRING); P_WriteUINT8(save_p, ARCH_SMALLSTRING);
WRITEUINT8(save_p, len); // save size of string P_WriteUINT8(save_p, len); // save size of string
} }
else else
{ {
WRITEUINT8(save_p, ARCH_LARGESTRING); P_WriteUINT8(save_p, ARCH_LARGESTRING);
WRITEUINT32(save_p, len); // save size of string P_WriteUINT32(save_p, len); // save size of string
} }
while (i < len) while (i < len)
WRITECHAR(save_p, s[i++]); // write chars individually, including the embedded zeros P_WriteChar(save_p, s[i++]); // write chars individually, including the embedded zeros
break; break;
} }
case LUA_TTABLE: case LUA_TTABLE:
@ -1186,13 +1186,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
if (t == 0) if (t == 0)
{ {
CONS_Alert(CONS_ERROR, "Too many tables to archive!\n"); CONS_Alert(CONS_ERROR, "Too many tables to archive!\n");
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 0; return 0;
} }
} }
WRITEUINT8(save_p, ARCH_TABLE); P_WriteUINT8(save_p, ARCH_TABLE);
WRITEUINT16(save_p, t); P_WriteUINT16(save_p, t);
if (!found) if (!found)
{ {
@ -1208,25 +1208,25 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
case ARCH_MOBJINFO: case ARCH_MOBJINFO:
{ {
mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex)); mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOBJINFO); P_WriteUINT8(save_p, ARCH_MOBJINFO);
WRITEUINT16(save_p, info - mobjinfo); P_WriteUINT16(save_p, info - mobjinfo);
break; break;
} }
case ARCH_STATE: case ARCH_STATE:
{ {
state_t *state = *((state_t **)lua_touserdata(gL, myindex)); state_t *state = *((state_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_STATE); P_WriteUINT8(save_p, ARCH_STATE);
WRITEUINT16(save_p, state - states); P_WriteUINT16(save_p, state - states);
break; break;
} }
case ARCH_MOBJ: case ARCH_MOBJ:
{ {
mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex)); mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex));
if (!mobj) if (!mobj)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MOBJ); P_WriteUINT8(save_p, ARCH_MOBJ);
WRITEUINT32(save_p, mobj->mobjnum); P_WriteUINT32(save_p, mobj->mobjnum);
} }
break; break;
} }
@ -1234,10 +1234,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
player_t *player = *((player_t **)lua_touserdata(gL, myindex)); player_t *player = *((player_t **)lua_touserdata(gL, myindex));
if (!player) if (!player)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_PLAYER); P_WriteUINT8(save_p, ARCH_PLAYER);
WRITEUINT8(save_p, player - players); P_WriteUINT8(save_p, player - players);
} }
break; break;
} }
@ -1245,10 +1245,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex)); mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex));
if (!mapthing) if (!mapthing)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MAPTHING); P_WriteUINT8(save_p, ARCH_MAPTHING);
WRITEUINT16(save_p, mapthing - mapthings); P_WriteUINT16(save_p, mapthing - mapthings);
} }
break; break;
} }
@ -1256,10 +1256,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex)); vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex));
if (!vertex) if (!vertex)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_VERTEX); P_WriteUINT8(save_p, ARCH_VERTEX);
WRITEUINT16(save_p, vertex - vertexes); P_WriteUINT16(save_p, vertex - vertexes);
} }
break; break;
} }
@ -1267,10 +1267,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
line_t *line = *((line_t **)lua_touserdata(gL, myindex)); line_t *line = *((line_t **)lua_touserdata(gL, myindex));
if (!line) if (!line)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_LINE); P_WriteUINT8(save_p, ARCH_LINE);
WRITEUINT16(save_p, line - lines); P_WriteUINT16(save_p, line - lines);
} }
break; break;
} }
@ -1278,10 +1278,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
side_t *side = *((side_t **)lua_touserdata(gL, myindex)); side_t *side = *((side_t **)lua_touserdata(gL, myindex));
if (!side) if (!side)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SIDE); P_WriteUINT8(save_p, ARCH_SIDE);
WRITEUINT16(save_p, side - sides); P_WriteUINT16(save_p, side - sides);
} }
break; break;
} }
@ -1289,10 +1289,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex)); subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex));
if (!subsector) if (!subsector)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SUBSECTOR); P_WriteUINT8(save_p, ARCH_SUBSECTOR);
WRITEUINT16(save_p, subsector - subsectors); P_WriteUINT16(save_p, subsector - subsectors);
} }
break; break;
} }
@ -1300,10 +1300,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex)); sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex));
if (!sector) if (!sector)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SECTOR); P_WriteUINT8(save_p, ARCH_SECTOR);
WRITEUINT16(save_p, sector - sectors); P_WriteUINT16(save_p, sector - sectors);
} }
break; break;
} }
@ -1312,10 +1312,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex)); seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex));
if (!seg) if (!seg)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SEG); P_WriteUINT8(save_p, ARCH_SEG);
WRITEUINT16(save_p, seg - segs); P_WriteUINT16(save_p, seg - segs);
} }
break; break;
} }
@ -1323,10 +1323,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
node_t *node = *((node_t **)lua_touserdata(gL, myindex)); node_t *node = *((node_t **)lua_touserdata(gL, myindex));
if (!node) if (!node)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_NODE); P_WriteUINT8(save_p, ARCH_NODE);
WRITEUINT16(save_p, node - nodes); P_WriteUINT16(save_p, node - nodes);
} }
break; break;
} }
@ -1335,16 +1335,16 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex)); ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex));
if (!rover) if (!rover)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
UINT16 i = P_GetFFloorID(rover); UINT16 i = P_GetFFloorID(rover);
if (i == UINT16_MAX) // invalid ID if (i == UINT16_MAX) // invalid ID
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else else
{ {
WRITEUINT8(save_p, ARCH_FFLOOR); P_WriteUINT8(save_p, ARCH_FFLOOR);
WRITEUINT16(save_p, rover->target - sectors); P_WriteUINT16(save_p, rover->target - sectors);
WRITEUINT16(save_p, i); P_WriteUINT16(save_p, i);
} }
} }
break; break;
@ -1353,10 +1353,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex)); polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex));
if (!polyobj) if (!polyobj)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_POLYOBJ); P_WriteUINT8(save_p, ARCH_POLYOBJ);
WRITEUINT16(save_p, polyobj-PolyObjects); P_WriteUINT16(save_p, polyobj-PolyObjects);
} }
break; break;
} }
@ -1364,10 +1364,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex)); pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex));
if (!slope) if (!slope)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SLOPE); P_WriteUINT8(save_p, ARCH_SLOPE);
WRITEUINT16(save_p, slope->id); P_WriteUINT16(save_p, slope->id);
} }
break; break;
} }
@ -1375,36 +1375,36 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex)); mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
if (!header) if (!header)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MAPHEADER); P_WriteUINT8(save_p, ARCH_MAPHEADER);
WRITEUINT16(save_p, header - *mapheaderinfo); P_WriteUINT16(save_p, header - *mapheaderinfo);
} }
break; break;
} }
case ARCH_SKINCOLOR: case ARCH_SKINCOLOR:
{ {
skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex)); skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKINCOLOR); P_WriteUINT8(save_p, ARCH_SKINCOLOR);
WRITEUINT16(save_p, info - skincolors); P_WriteUINT16(save_p, info - skincolors);
break; break;
} }
case ARCH_MOUSE: case ARCH_MOUSE:
{ {
mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex)); mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOUSE); P_WriteUINT8(save_p, ARCH_MOUSE);
WRITEUINT8(save_p, m == &mouse ? 1 : 2); P_WriteUINT8(save_p, m == &mouse ? 1 : 2);
break; break;
} }
case ARCH_SKIN: case ARCH_SKIN:
{ {
skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex)); skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKIN); P_WriteUINT8(save_p, ARCH_SKIN);
WRITEUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256 P_WriteUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256
break; break;
} }
default: default:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 2; return 2;
} }
break; break;
@ -1412,14 +1412,14 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
return 0; return 0;
} }
static void ArchiveExtVars(void *pointer, const char *ptype) static void ArchiveExtVars(save_t *save_p, void *pointer, const char *ptype)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i; UINT16 i;
if (!gL) { if (!gL) {
if (fastcmp(ptype,"player")) // players must always be included, even if no vars if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
return; return;
} }
@ -1435,7 +1435,7 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
{ // no extra values table { // no extra values table
lua_pop(gL, 1); lua_pop(gL, 1);
if (fastcmp(ptype,"player")) // players must always be included, even if no vars if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
return; return;
} }
@ -1447,20 +1447,20 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
if (i == 0) if (i == 0)
{ {
if (fastcmp(ptype,"player")) // always include players even if they have no extra variables if (fastcmp(ptype,"player")) // always include players even if they have no extra variables
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
lua_pop(gL, 1); lua_pop(gL, 1);
return; return;
} }
if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header
WRITEUINT32(save_p, ((mobj_t *)pointer)->mobjnum); P_WriteUINT32(save_p, ((mobj_t *)pointer)->mobjnum);
WRITEUINT16(save_p, i); P_WriteUINT16(save_p, i);
lua_pushnil(gL); lua_pushnil(gL);
while (lua_next(gL, -2)) while (lua_next(gL, -2))
{ {
I_Assert(lua_type(gL, -2) == LUA_TSTRING); I_Assert(lua_type(gL, -2) == LUA_TSTRING);
WRITESTRING(save_p, lua_tostring(gL, -2)); P_WriteString(save_p, lua_tostring(gL, -2));
if (ArchiveValue(TABLESINDEX, -1) == 2) if (ArchiveValue(save_p, TABLESINDEX, -1) == 2)
CONS_Alert(CONS_ERROR, "Type of value for %s entry '%s' (%s) could not be archived!\n", ptype, lua_tostring(gL, -2), luaL_typename(gL, -1)); CONS_Alert(CONS_ERROR, "Type of value for %s entry '%s' (%s) could not be archived!\n", ptype, lua_tostring(gL, -2), luaL_typename(gL, -1));
lua_pop(gL, 1); lua_pop(gL, 1);
} }
@ -1468,16 +1468,19 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
lua_pop(gL, 1); lua_pop(gL, 1);
} }
// FIXME: remove and pass as local variable
static save_t *lua_save_p;
static int NetArchive(lua_State *L) static int NetArchive(lua_State *L)
{ {
int TABLESINDEX = lua_upvalueindex(1); int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L); int i, n = lua_gettop(L);
for (i = 1; i <= n; i++) for (i = 1; i <= n; i++)
ArchiveValue(TABLESINDEX, i); ArchiveValue(lua_save_p, TABLESINDEX, i);
return n; return n;
} }
static void ArchiveTables(void) static void ArchiveTables(save_t *save_p)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i, n; UINT16 i, n;
@ -1496,14 +1499,14 @@ static void ArchiveTables(void)
while (lua_next(gL, -2)) while (lua_next(gL, -2))
{ {
// Write key // Write key
e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this. e = ArchiveValue(save_p, TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
if (e == 1) if (e == 1)
n++; // the table contained a new table we'll have to archive. :( n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise) else if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise)
CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -2), luaL_typename(gL, -2), i); CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -2), luaL_typename(gL, -2), i);
// Write value // Write value
e = ArchiveValue(TABLESINDEX, -1); e = ArchiveValue(save_p, TABLESINDEX, -1);
if (e == 1) if (e == 1)
n++; // the table contained a new table we'll have to archive. :( n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid value type else if (e == 2) // invalid value type
@ -1511,7 +1514,7 @@ static void ArchiveTables(void)
lua_pop(gL, 1); lua_pop(gL, 1);
} }
WRITEUINT8(save_p, ARCH_TEND); P_WriteUINT8(save_p, ARCH_TEND);
// Write metatable ID // Write metatable ID
if (lua_getmetatable(gL, -1)) if (lua_getmetatable(gL, -1))
@ -1520,19 +1523,19 @@ static void ArchiveTables(void)
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_pushvalue(gL, -2); lua_pushvalue(gL, -2);
lua_gettable(gL, -2); lua_gettable(gL, -2);
WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1)); P_WriteUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1));
lua_pop(gL, 3); lua_pop(gL, 3);
} }
else else
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
lua_pop(gL, 1); lua_pop(gL, 1);
} }
} }
static UINT8 UnArchiveValue(int TABLESINDEX) static UINT8 UnArchiveValue(save_t *save_p, int TABLESINDEX)
{ {
UINT8 type = READUINT8(save_p); UINT8 type = P_ReadUINT8(save_p);
switch (type) switch (type)
{ {
case ARCH_NULL: case ARCH_NULL:
@ -1545,13 +1548,13 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
lua_pushboolean(gL, false); lua_pushboolean(gL, false);
break; break;
case ARCH_INT8: case ARCH_INT8:
lua_pushinteger(gL, READSINT8(save_p)); lua_pushinteger(gL, P_ReadSINT8(save_p));
break; break;
case ARCH_INT16: case ARCH_INT16:
lua_pushinteger(gL, READINT16(save_p)); lua_pushinteger(gL, P_ReadINT16(save_p));
break; break;
case ARCH_INT32: case ARCH_INT32:
lua_pushinteger(gL, READFIXED(save_p)); lua_pushinteger(gL, P_ReadFixed(save_p));
break; break;
case ARCH_SMALLSTRING: case ARCH_SMALLSTRING:
case ARCH_LARGESTRING: case ARCH_LARGESTRING:
@ -1562,23 +1565,23 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
// See my comments in the ArchiveValue function; // See my comments in the ArchiveValue function;
// it's much the same for reading strings as writing them! // it's much the same for reading strings as writing them!
// (i.e. we can't use READSTRING either) // (i.e. we can't use P_ReadString either)
// -- Monster Iestyn 05/08/18 // -- Monster Iestyn 05/08/18
if (type == ARCH_SMALLSTRING) if (type == ARCH_SMALLSTRING)
len = READUINT8(save_p); // length of string, including embedded zeros len = P_ReadUINT8(save_p); // length of string, including embedded zeros
else else
len = READUINT32(save_p); // length of string, including embedded zeros len = P_ReadUINT32(save_p); // length of string, including embedded zeros
value = malloc(len); // make temp buffer of size len value = malloc(len); // make temp buffer of size len
// now read the actual string // now read the actual string
while (i < len) while (i < len)
value[i++] = READCHAR(save_p); // read chars individually, including the embedded zeros value[i++] = P_ReadChar(save_p); // read chars individually, including the embedded zeros
lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros) lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros)
free(value); // free the buffer free(value); // free the buffer
break; break;
} }
case ARCH_TABLE: case ARCH_TABLE:
{ {
UINT16 tid = READUINT16(save_p); UINT16 tid = P_ReadUINT16(save_p);
lua_rawgeti(gL, TABLESINDEX, tid); lua_rawgeti(gL, TABLESINDEX, tid);
if (lua_isnil(gL, -1)) if (lua_isnil(gL, -1))
{ {
@ -1591,69 +1594,69 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
break; break;
} }
case ARCH_MOBJINFO: case ARCH_MOBJINFO:
LUA_PushUserdata(gL, &mobjinfo[READUINT16(save_p)], META_MOBJINFO); LUA_PushUserdata(gL, &mobjinfo[P_ReadUINT16(save_p)], META_MOBJINFO);
break; break;
case ARCH_STATE: case ARCH_STATE:
LUA_PushUserdata(gL, &states[READUINT16(save_p)], META_STATE); LUA_PushUserdata(gL, &states[P_ReadUINT16(save_p)], META_STATE);
break; break;
case ARCH_MOBJ: case ARCH_MOBJ:
LUA_PushUserdata(gL, P_FindNewPosition(READUINT32(save_p)), META_MOBJ); LUA_PushUserdata(gL, P_FindNewPosition(P_ReadUINT32(save_p)), META_MOBJ);
break; break;
case ARCH_PLAYER: case ARCH_PLAYER:
LUA_PushUserdata(gL, &players[READUINT8(save_p)], META_PLAYER); LUA_PushUserdata(gL, &players[P_ReadUINT8(save_p)], META_PLAYER);
break; break;
case ARCH_MAPTHING: case ARCH_MAPTHING:
LUA_PushUserdata(gL, &mapthings[READUINT16(save_p)], META_MAPTHING); LUA_PushUserdata(gL, &mapthings[P_ReadUINT16(save_p)], META_MAPTHING);
break; break;
case ARCH_VERTEX: case ARCH_VERTEX:
LUA_PushUserdata(gL, &vertexes[READUINT16(save_p)], META_VERTEX); LUA_PushUserdata(gL, &vertexes[P_ReadUINT16(save_p)], META_VERTEX);
break; break;
case ARCH_LINE: case ARCH_LINE:
LUA_PushUserdata(gL, &lines[READUINT16(save_p)], META_LINE); LUA_PushUserdata(gL, &lines[P_ReadUINT16(save_p)], META_LINE);
break; break;
case ARCH_SIDE: case ARCH_SIDE:
LUA_PushUserdata(gL, &sides[READUINT16(save_p)], META_SIDE); LUA_PushUserdata(gL, &sides[P_ReadUINT16(save_p)], META_SIDE);
break; break;
case ARCH_SUBSECTOR: case ARCH_SUBSECTOR:
LUA_PushUserdata(gL, &subsectors[READUINT16(save_p)], META_SUBSECTOR); LUA_PushUserdata(gL, &subsectors[P_ReadUINT16(save_p)], META_SUBSECTOR);
break; break;
case ARCH_SECTOR: case ARCH_SECTOR:
LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_SECTOR); LUA_PushUserdata(gL, &sectors[P_ReadUINT16(save_p)], META_SECTOR);
break; break;
#ifdef HAVE_LUA_SEGS #ifdef HAVE_LUA_SEGS
case ARCH_SEG: case ARCH_SEG:
LUA_PushUserdata(gL, &segs[READUINT16(save_p)], META_SEG); LUA_PushUserdata(gL, &segs[P_ReadUINT16(save_p)], META_SEG);
break; break;
case ARCH_NODE: case ARCH_NODE:
LUA_PushUserdata(gL, &nodes[READUINT16(save_p)], META_NODE); LUA_PushUserdata(gL, &nodes[P_ReadUINT16(save_p)], META_NODE);
break; break;
#endif #endif
case ARCH_FFLOOR: case ARCH_FFLOOR:
{ {
sector_t *sector = &sectors[READUINT16(save_p)]; sector_t *sector = &sectors[P_ReadUINT16(save_p)];
UINT16 id = READUINT16(save_p); UINT16 id = P_ReadUINT16(save_p);
ffloor_t *rover = P_GetFFloorByID(sector, id); ffloor_t *rover = P_GetFFloorByID(sector, id);
if (rover) if (rover)
LUA_PushUserdata(gL, rover, META_FFLOOR); LUA_PushUserdata(gL, rover, META_FFLOOR);
break; break;
} }
case ARCH_POLYOBJ: case ARCH_POLYOBJ:
LUA_PushUserdata(gL, &PolyObjects[READUINT16(save_p)], META_POLYOBJ); LUA_PushUserdata(gL, &PolyObjects[P_ReadUINT16(save_p)], META_POLYOBJ);
break; break;
case ARCH_SLOPE: case ARCH_SLOPE:
LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE); LUA_PushUserdata(gL, P_SlopeById(P_ReadUINT16(save_p)), META_SLOPE);
break; break;
case ARCH_MAPHEADER: case ARCH_MAPHEADER:
LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER); LUA_PushUserdata(gL, mapheaderinfo[P_ReadUINT16(save_p)], META_MAPHEADER);
break; break;
case ARCH_SKINCOLOR: case ARCH_SKINCOLOR:
LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR); LUA_PushUserdata(gL, &skincolors[P_ReadUINT16(save_p)], META_SKINCOLOR);
break; break;
case ARCH_MOUSE: case ARCH_MOUSE:
LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE); LUA_PushUserdata(gL, P_ReadUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE);
break; break;
case ARCH_SKIN: case ARCH_SKIN:
LUA_PushUserdata(gL, skins[READUINT8(save_p)], META_SKIN); LUA_PushUserdata(gL, skins[P_ReadUINT8(save_p)], META_SKIN);
break; break;
case ARCH_TEND: case ARCH_TEND:
return 1; return 1;
@ -1661,10 +1664,10 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
return 0; return 0;
} }
static void UnArchiveExtVars(void *pointer) static void UnArchiveExtVars(save_t *save_p, void *pointer)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 field_count = READUINT16(save_p); UINT16 field_count = P_ReadUINT16(save_p);
UINT16 i; UINT16 i;
char field[1024]; char field[1024];
@ -1677,8 +1680,8 @@ static void UnArchiveExtVars(void *pointer)
for (i = 0; i < field_count; i++) for (i = 0; i < field_count; i++)
{ {
READSTRING(save_p, field); P_ReadString(save_p, field);
UnArchiveValue(TABLESINDEX); UnArchiveValue(save_p, TABLESINDEX);
lua_setfield(gL, -2, field); lua_setfield(gL, -2, field);
} }
@ -1695,11 +1698,11 @@ static int NetUnArchive(lua_State *L)
int TABLESINDEX = lua_upvalueindex(1); int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L); int i, n = lua_gettop(L);
for (i = 1; i <= n; i++) for (i = 1; i <= n; i++)
UnArchiveValue(TABLESINDEX); UnArchiveValue(lua_save_p, TABLESINDEX);
return n; return n;
} }
static void UnArchiveTables(void) static void UnArchiveTables(save_t *save_p)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i, n; UINT16 i, n;
@ -1716,13 +1719,13 @@ static void UnArchiveTables(void)
lua_rawgeti(gL, TABLESINDEX, i); lua_rawgeti(gL, TABLESINDEX, i);
while (true) while (true)
{ {
UINT8 e = UnArchiveValue(TABLESINDEX); // read key UINT8 e = UnArchiveValue(save_p, TABLESINDEX); // read key
if (e == 1) // End of table if (e == 1) // End of table
break; break;
else if (e == 2) // Key contains a new table else if (e == 2) // Key contains a new table
n++; n++;
if (UnArchiveValue(TABLESINDEX) == 2) // read value if (UnArchiveValue(save_p, TABLESINDEX) == 2) // read value
n++; n++;
if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved) if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved)
@ -1734,7 +1737,7 @@ static void UnArchiveTables(void)
lua_rawset(gL, -3); lua_rawset(gL, -3);
} }
metatableid = READUINT16(save_p); metatableid = P_ReadUINT16(save_p);
if (metatableid) if (metatableid)
{ {
// setmetatable(table, registry.metatables[metatableid]) // setmetatable(table, registry.metatables[metatableid])
@ -1758,7 +1761,7 @@ void LUA_Step(void)
lua_gc(gL, LUA_GCSTEP, 1); lua_gc(gL, LUA_GCSTEP, 1);
} }
void LUA_Archive(void) void LUA_Archive(save_t *save_p)
{ {
INT32 i; INT32 i;
thinker_t *th; thinker_t *th;
@ -1771,29 +1774,30 @@ void LUA_Archive(void)
if (!playeringame[i] && i > 0) // dedicated servers... if (!playeringame[i] && i > 0) // dedicated servers...
continue; continue;
// all players in game will be archived, even if they just add a 0. // all players in game will be archived, even if they just add a 0.
ArchiveExtVars(&players[i], "player"); ArchiveExtVars(save_p, &players[i], "player");
} }
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
// archive function will determine when to skip mobjs, // archive function will determine when to skip mobjs,
// and write mobjnum in otherwise. // and write mobjnum in otherwise.
ArchiveExtVars(th, "mobj"); ArchiveExtVars(save_p, th, "mobj");
} }
WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. P_WriteUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
lua_save_p = save_p;
LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode
ArchiveTables(); ArchiveTables(save_p);
if (gL) if (gL)
lua_pop(gL, 1); // pop tables lua_pop(gL, 1); // pop tables
} }
void LUA_UnArchive(void) void LUA_UnArchive(save_t *save_p)
{ {
UINT32 mobjnum; UINT32 mobjnum;
INT32 i; INT32 i;
@ -1806,23 +1810,24 @@ void LUA_UnArchive(void)
{ {
if (!playeringame[i] && i > 0) // dedicated servers... if (!playeringame[i] && i > 0) // dedicated servers...
continue; continue;
UnArchiveExtVars(&players[i]); UnArchiveExtVars(save_p, &players[i]);
} }
do { do {
mobjnum = READUINT32(save_p); // read a mobjnum mobjnum = P_ReadUINT32(save_p); // read a mobjnum
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
continue; continue;
UnArchiveExtVars(th); // apply variables UnArchiveExtVars(save_p, th); // apply variables
} }
} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
lua_save_p = save_p;
LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode
UnArchiveTables(); UnArchiveTables(save_p);
if (gL) if (gL)
lua_pop(gL, 1); // pop tables lua_pop(gL, 1); // pop tables

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -13,6 +13,7 @@
#ifndef LUA_SCRIPT_H #ifndef LUA_SCRIPT_H
#define LUA_SCRIPT_H #define LUA_SCRIPT_H
#include "p_saveg.h"
#include "m_fixed.h" #include "m_fixed.h"
#include "doomtype.h" #include "doomtype.h"
#include "d_player.h" #include "d_player.h"
@ -52,8 +53,8 @@ void LUA_DumpFile(const char *filename);
#endif #endif
fixed_t LUA_EvalMath(const char *word); fixed_t LUA_EvalMath(const char *word);
void LUA_Step(void); void LUA_Step(void);
void LUA_Archive(void); void LUA_Archive(save_t *save_p);
void LUA_UnArchive(void); void LUA_UnArchive(save_t *save_p);
int LUA_PushGlobals(lua_State *L, const char *word); int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_CheckGlobals(lua_State *L, const char *word); int LUA_CheckGlobals(lua_State *L, const char *word);
void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2014-2016 by John "JTE" Muniz. // Copyright (C) 2014-2016 by John "JTE" Muniz.
// Copyright (C) 2014-2023 by Sonic Team Junior. // Copyright (C) 2014-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2013 by "Ninji". // Copyright (C) 2013 by "Ninji".
// Copyright (C) 2013-2023 by Sonic Team Junior. // Copyright (C) 2013-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -562,7 +562,7 @@ void Command_Teleport_f(void)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
mo2 = (mobj_t *)th; mo2 = (mobj_t *)th;
@ -1072,7 +1072,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
mo = (mobj_t *)th; mo = (mobj_t *)th;

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 2012-2023 by Sonic Team Junior. // Copyright (C) 2012-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -494,6 +494,12 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data) UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data)
{ {
if (dedicated)
{
// See M_MapLocked; don't make dedicated servers annoying.
return false;
}
if (M_MapLocked(mapnum, data) == true) if (M_MapLocked(mapnum, data) == true)
{ {
// Warping to locked maps is definitely always a cheat // Warping to locked maps is definitely always a cheat

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos. // Copyright (C) 2020-2023 by Lactozilla.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos. // Copyright (C) 2020-2023 by Lactozilla.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// Copyright (C) 2009 by Stephen McGranahan. // Copyright (C) 2009 by Stephen McGranahan.
// //
// This program is free software distributed under the // This program is free software distributed under the

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -3,7 +3,7 @@
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -140,6 +140,7 @@ static char *char_notes = NULL;
boolean menuactive = false; boolean menuactive = false;
boolean fromlevelselect = false; boolean fromlevelselect = false;
tic_t shieldprompt_timer = 0; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove
typedef enum typedef enum
{ {
@ -3161,6 +3162,7 @@ static void Command_Manual_f(void)
if (modeattacking) if (modeattacking)
return; return;
M_StartControlPanel(); M_StartControlPanel();
if (shieldprompt_timer) return; // TODO: 2.3: Delete this line
currentMenu = &MISC_HelpDef; currentMenu = &MISC_HelpDef;
itemOn = 0; itemOn = 0;
} }
@ -3316,7 +3318,7 @@ boolean M_Responder(event_t *ev)
if (ch == -1) if (ch == -1)
return false; return false;
else if (ch == gamecontrol[GC_SYSTEMMENU][0] || ch == gamecontrol[GC_SYSTEMMENU][1]) // allow remappable ESC key else if (ev->type != ev_text && (ch == gamecontrol[GC_SYSTEMMENU][0] || ch == gamecontrol[GC_SYSTEMMENU][1])) // allow remappable ESC key
ch = KEY_ESCAPE; ch = KEY_ESCAPE;
// F-Keys // F-Keys
@ -3340,6 +3342,7 @@ boolean M_Responder(event_t *ev)
if (modeattacking) if (modeattacking)
return true; return true;
M_StartControlPanel(); M_StartControlPanel();
if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line
M_Options(0); M_Options(0);
// Uncomment the below if you want the menu to reset to the top each time like before. M_SetupNextMenu will fix it automatically. // Uncomment the below if you want the menu to reset to the top each time like before. M_SetupNextMenu will fix it automatically.
//OP_SoundOptionsDef.lastOn = 0; //OP_SoundOptionsDef.lastOn = 0;
@ -3350,6 +3353,7 @@ boolean M_Responder(event_t *ev)
if (modeattacking) if (modeattacking)
return true; return true;
M_StartControlPanel(); M_StartControlPanel();
if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line
M_Options(0); M_Options(0);
M_VideoModeMenu(0); M_VideoModeMenu(0);
return true; return true;
@ -3361,6 +3365,7 @@ boolean M_Responder(event_t *ev)
if (modeattacking) if (modeattacking)
return true; return true;
M_StartControlPanel(); M_StartControlPanel();
if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line
M_Options(0); M_Options(0);
M_SetupNextMenu(&OP_MainDef); M_SetupNextMenu(&OP_MainDef);
return true; return true;
@ -3394,9 +3399,16 @@ boolean M_Responder(event_t *ev)
// Handle menuitems which need a specific key handling // Handle menuitems which need a specific key handling
if (routine && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER) if (routine && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER)
{ {
// block text input if ctrl is held, to allow using ctrl+c ctrl+v and ctrl+x
if (ctrldown)
{
routine(ch);
return true;
}
// ignore ev_keydown events if the key maps to a character, since // ignore ev_keydown events if the key maps to a character, since
// the ev_text event will follow immediately after in that case. // the ev_text event will follow immediately after in that case.
if (ev->type == ev_keydown && ch >= 32 && ch <= 127) if (ev->type == ev_keydown && ((ch >= 32 && ch <= 127) || (ch >= KEY_KEYPAD7 && ch <= KEY_KPADDEL)))
return true; return true;
routine(ch); routine(ch);
@ -3424,7 +3436,7 @@ boolean M_Responder(event_t *ev)
{ {
// dirty hack: for customising controls, I want only buttons/keys, not moves // dirty hack: for customising controls, I want only buttons/keys, not moves
if (ev->type == ev_mouse || ev->type == ev_mouse2 || ev->type == ev_joystick if (ev->type == ev_mouse || ev->type == ev_mouse2 || ev->type == ev_joystick
|| ev->type == ev_joystick2) || ev->type == ev_joystick2 || ev->type == ev_text)
return true; return true;
if (routine) if (routine)
{ {
@ -3631,6 +3643,230 @@ void M_Drawer(void)
} }
} }
// Handle the "Do you want to assign Shield Ability now?" pop-up for old configs // TODO: 2.3: Remove this line...
static UINT8 shieldprompt_currentchoice = 0; // ...and this line...
static void M_ShieldPromptUseDefaults(void) // ...and this function
{
// With a default config from v2.2.10 to v2.2.13, the B button will be set to Custom 1,
// and Controls per Key defaults to "One", so it will override the default Shield button.
// A default config from v2.2.0 to v2.2.9 has Next Weapon on B, so it suffers from this too.
// So for "Use default Shield Ability buttons", we should update old configs to mitigate gamepad conflicts
// (even with "Several" Controls per Key!), and show a message with the default bindings
for (setupcontrols = gamecontrol; true; setupcontrols = gamecontrolbis) // Do stuff for both P1 and P2
{
INT32 JOY1 = (setupcontrols == gamecontrol) ? KEY_JOY1 : KEY_2JOY1; // Is this for P1 or for P2?
if ((setupcontrols[GC_CUSTOM1][0] == JOY1+1 || setupcontrols[GC_CUSTOM1][1] == JOY1+1)
&& (setupcontrols[GC_CUSTOM2][0] == JOY1+3 || setupcontrols[GC_CUSTOM2][1] == JOY1+3)
&& (setupcontrols[GC_CUSTOM3][0] == JOY1+8 || setupcontrols[GC_CUSTOM3][1] == JOY1+8))
{
// If the player has v2.2.13's default gamepad Custom 1/2/3 buttons,
// shuffle Custom 1/2/3 around to make room for Shield Ability on B
UINT8 shield_slot = (setupcontrols[GC_SHIELD ][0] == KEY_NULL ) ? 0 : 1;
UINT8 custom1_slot = (setupcontrols[GC_CUSTOM1][0] == JOY1+1) ? 0 : 1;
UINT8 custom2_slot = (setupcontrols[GC_CUSTOM2][0] == JOY1+3) ? 0 : 1;
UINT8 custom3_slot = (setupcontrols[GC_CUSTOM3][0] == JOY1+8) ? 0 : 1;
setupcontrols[GC_SHIELD ][shield_slot ] = JOY1+1; // Assign Shield Ability to B
setupcontrols[GC_CUSTOM1][custom1_slot] = JOY1+3; // Move Custom 1 from B to Y
setupcontrols[GC_CUSTOM2][custom2_slot] = JOY1+8; // Move Custom 2 from Y to LS
setupcontrols[GC_CUSTOM3][custom3_slot] = KEY_NULL; // Unassign Custom 3 from LS...
// (The alternative would be to check and update the ENTIRE gamepad layout.
// That'd be nice, but it would mess with people that are used to the old defaults.)
}
else if ((setupcontrols[GC_WEAPONNEXT][0] == JOY1+1 || setupcontrols[GC_WEAPONNEXT][1] == JOY1+1)
&& (setupcontrols[GC_WEAPONPREV][0] == JOY1+2 || setupcontrols[GC_WEAPONPREV][1] == JOY1+2))
{
// Or if the user has a default config from v2.2.0 to v2.2.9,
// the B button will be Next Weapon, and X will be Previous Weapon.
// It's "safe" to discard one of them, you just have to press X multiple times to select in the other direction
UINT8 shield_slot = (setupcontrols[GC_SHIELD ][0] == KEY_NULL ) ? 0 : 1;
UINT8 nweapon_slot = (setupcontrols[GC_WEAPONNEXT][0] == JOY1+1) ? 0 : 1;
UINT8 pweapon_slot = (setupcontrols[GC_WEAPONPREV][0] == JOY1+2) ? 0 : 1;
setupcontrols[GC_SHIELD ][shield_slot ] = JOY1+1; // Assign Shield Ability to B
setupcontrols[GC_WEAPONNEXT][nweapon_slot] = JOY1+3; // Move Next Weapon from B to X
setupcontrols[GC_WEAPONPREV][pweapon_slot] = KEY_NULL; // Unassign Previous Weapon from X
}
if (setupcontrols == gamecontrolbis) // If we've already updated both players, break out
break;
}
// Now, show a message about the default Shield Ability bindings
if ((gamecontrol[GC_SHIELD][0] == KEY_LALT && gamecontrol[GC_SHIELD][1] == KEY_JOY1+1)
|| (gamecontrol[GC_SHIELD][0] == KEY_JOY1+1 && gamecontrol[GC_SHIELD][1] == KEY_LALT))
{
// Left Alt and the B button are both assigned
M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x82""Left Alt\x80"" key on keyboard,\nand the \x85""B button\x80"" on gamepads."
"\n\nYou can always reassign it\nin the Options menu later."
"\n\n\nPress 'Enter' to continue\n"),
NULL, MM_NOTHING);
MessageDef.x = 43; // Change the pop-up message's background position/width
MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 27;
}
else if (gamecontrol[GC_SHIELD][0] == KEY_LALT || gamecontrol[GC_SHIELD][1] == KEY_LALT)
{
// Left Alt is assigned, but the B button isn't.
M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x82""Left Alt\x80"" key on keyboard.\nThe \x85""B button\x80"" on gamepads was taken."
"\n\nYou can always reassign it\nin the Options menu later."
"\n\n\nPress 'Enter' to continue\n"),
NULL, MM_NOTHING);
MessageDef.x = 24; // Change the pop-up message's background position/width
MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 32;
}
else if (gamecontrol[GC_SHIELD][0] == KEY_JOY1+1 || gamecontrol[GC_SHIELD][1] == KEY_JOY1+1)
{
// The B button is assigned, but Left Alt isn't
M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x85""B button\x80"" on gamepads.\nThe \x82""Left Alt\x80"" key on keyboard was taken."
"\n\nYou can always reassign it\nin the Options menu later."
"\n\n\nPress 'Enter' to continue\n"),
NULL, MM_NOTHING);
MessageDef.x = 8; // Change the pop-up message's background position/width
MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 36;
}
else if (gamecontrol[GC_SHIELD][0] == KEY_NULL && gamecontrol[GC_SHIELD][1] == KEY_NULL)
{
// Neither Left Alt nor the B button are assigned
M_StartMessage(M_GetText("Shield Ability is unassigned!\nThe \x82""Left Alt\x80"" key on keyboard and\nthe \x85""B button\x80"" on gamepads were taken."
"\n\nYou should assign Shield Ability\nin the Options menu later."
"\n\n\nPress 'Enter' to continue\n"),
NULL, MM_NOTHING);
MessageDef.x = 19; // Change the pop-up message's background position/width
MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 33;
}
else
{
// Neither Left Alt nor the B button are assigned... but something else is???
// (This can technically happen if you edit your config or use setcontrol in the console before opening the menu)
char keystr[16+16+2+7+1]; // Two 16-char keys + two colour codes + "' and '" + null
if (gamecontrol[GC_SHIELD][0] != KEY_NULL && gamecontrol[GC_SHIELD][1] != KEY_NULL)
STRBUFCPY(keystr, va("%s\x80""' and '\x82""%s",
G_KeyNumToName(gamecontrol[GC_SHIELD][0]),
G_KeyNumToName(gamecontrol[GC_SHIELD][1])));
else if (gamecontrol[GC_SHIELD][0] != KEY_NULL)
STRBUFCPY(keystr, G_KeyNumToName(gamecontrol[GC_SHIELD][0]));
else //if (gamecontrol[GC_SHIELD][1] != KEY_NULL)
STRBUFCPY(keystr, G_KeyNumToName(gamecontrol[GC_SHIELD][1]));
M_StartMessage(va("Shield Ability is assigned to\n'\x82""%s\x80""'."
"\n\nYou can always reassign it\nin the Options menu later."
"\n\n\nPress 'Enter' to continue\n",
keystr), NULL, MM_NOTHING);
MessageDef.x = 23; // Change the pop-up message's background position/width
MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 32;
}
}
static void M_HandleShieldPromptMenu(INT32 choice) // TODO: 2.3: Remove
{
switch (choice)
{
case KEY_ESCAPE:
if (I_GetTime() <= shieldprompt_timer) // Don't mash past the pop-up by accident!
break;
S_StartSound(NULL, sfx_menu1);
noFurtherInput = true;
shieldprompt_timer = 0;
M_ShieldPromptUseDefaults();
break;
case KEY_ENTER:
if (I_GetTime() <= shieldprompt_timer) // Don't mash past the pop-up by accident!
break;
S_StartSound(NULL, sfx_menu1);
noFurtherInput = true;
shieldprompt_timer = 0;
if (shieldprompt_currentchoice == 0)
{
OP_ChangeControlsDef.lastOn = 8; // Highlight Shield Ability in the controls menu
M_Setup1PControlsMenu(0); // Set up P1's controls menu and call M_SetupNextMenu
}
else if (shieldprompt_currentchoice == 1) // Copy the Spin buttons to the Shield buttons
{
CV_SetValue(&cv_controlperkey, 2); // Make sure that Controls per Key is "Several"
gamecontrol [GC_SHIELD][0] = gamecontrol [GC_SPIN][0];
gamecontrol [GC_SHIELD][1] = gamecontrol [GC_SPIN][1];
gamecontrolbis[GC_SHIELD][0] = gamecontrolbis[GC_SPIN][0];
gamecontrolbis[GC_SHIELD][1] = gamecontrolbis[GC_SPIN][1];
CV_SetValue(&cv_shieldaxis, cv_spinaxis.value);
CV_SetValue(&cv_shieldaxis2, cv_spinaxis2.value);
M_StartMessage(M_GetText("Spin and Shield Ability are now\nthe same button."
"\n\nYou can always reassign them\nin the Options menu later."
"\n\n\nPress 'Enter' to continue\n"),
NULL, MM_NOTHING);
MessageDef.x = 36; // Change the pop-up message's background position/width
MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 29;
}
else
M_ShieldPromptUseDefaults();
break;
case KEY_UPARROW:
S_StartSound(NULL, sfx_menu1);
shieldprompt_currentchoice = (shieldprompt_currentchoice+2)%3;
break;
case KEY_DOWNARROW:
S_StartSound(NULL, sfx_menu1);
shieldprompt_currentchoice = (shieldprompt_currentchoice+1)%3;
break;
}
MessageDef.prevMenu = &MainDef;
}
static void M_DrawShieldPromptMenu(void) // TODO: 2.3: Remove
{
INT16 cursorx = (BASEVIDWIDTH/2) - 24;
V_DrawFill(10-3, 68-3, 300+6, 40+6, 159);
// V_DrawCenteredString doesn't centre newlines, so we have to draw each line separately
V_DrawCenteredString(BASEVIDWIDTH/2, 68, V_ALLOWLOWERCASE, "Welcome back! Since you last played,");
V_DrawCenteredString(BASEVIDWIDTH/2, 76, V_ALLOWLOWERCASE, "Spin has been split into separate");
V_DrawCenteredString(BASEVIDWIDTH/2, 84, V_ALLOWLOWERCASE, "\"Spin\" and \"Shield Ability\" controls.");
V_DrawCenteredString(BASEVIDWIDTH/2, 98, V_ALLOWLOWERCASE, "Do you want to assign Shield Ability now?");
V_DrawCenteredString(BASEVIDWIDTH/2, 164,
(shieldprompt_currentchoice == 0) ? V_YELLOWMAP : 0, "Open Control Setup");
V_DrawCenteredString(BASEVIDWIDTH/2, 172,
(shieldprompt_currentchoice == 1) ? V_YELLOWMAP : 0, "Keep the old behaviour");
V_DrawCenteredString(BASEVIDWIDTH/2, 180,
(shieldprompt_currentchoice == 2) ? V_YELLOWMAP : 0, "Use default Shield Ability buttons");
switch (shieldprompt_currentchoice)
{
case 0: cursorx -= V_StringWidth("Open Control Setup", 0)/2; break;
case 1: cursorx -= V_StringWidth("Keep the old behaviour", 0)/2; break;
default: cursorx -= V_StringWidth("Use default Shield Ability buttons", 0)/2; break;
}
V_DrawScaledPatch(cursorx, 164 + (shieldprompt_currentchoice*8), 0, W_CachePatchName("M_CURSOR", PU_PATCH));
}
static menuitem_t OP_ShieldPromptMenu[] = {{IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleShieldPromptMenu, 0}}; // TODO: 2.3: Remove
menu_t OP_ShieldPromptDef = { // TODO: 2.3: Remove
MN_SPECIAL,
NULL,
1,
&MainDef,
OP_ShieldPromptMenu,
M_DrawShieldPromptMenu,
0, 0, 0, NULL
};
// //
// M_StartControlPanel // M_StartControlPanel
// //
@ -3662,6 +3898,15 @@ void M_StartControlPanel(void)
currentMenu = &MainDef; currentMenu = &MainDef;
itemOn = singleplr; itemOn = singleplr;
M_UpdateItemOn(); M_UpdateItemOn();
if (shieldprompt_timer) // For old configs, show a pop-up about the new Shield button // TODO: 2.3: Remove
{
S_StartSound(NULL, sfx_strpst);
noFurtherInput = true;
shieldprompt_timer = I_GetTime() + TICRATE; // Don't mash past the pop-up by accident!
M_SetupNextMenu(&OP_ShieldPromptDef);
}
} }
else if (modeattacking) else if (modeattacking)
{ {
@ -8273,6 +8518,7 @@ static void M_StartTutorial(INT32 choice)
gamecomplete = 0; gamecomplete = 0;
cursaveslot = 0; cursaveslot = 0;
maplistoption = 0; maplistoption = 0;
CV_StealthSet(&cv_skin, DEFAULTSKIN); // tutorial accounts for sonic only
G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false); G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false);
} }
@ -8372,7 +8618,7 @@ static void M_DrawLoadGameData(void)
if (savegameinfo[savetodraw].lives == -42) if (savegameinfo[savetodraw].lives == -42)
col = 26; col = 26;
else if (savegameinfo[savetodraw].botskin == 3) // & knuckles else if (savegameinfo[savetodraw].botskin == 3) // & knuckles
col = 105; col = 106;
else if (savegameinfo[savetodraw].botskin) // tailsbot or custom else if (savegameinfo[savetodraw].botskin) // tailsbot or custom
col = 134; col = 134;
else else
@ -8432,7 +8678,17 @@ static void M_DrawLoadGameData(void)
if (savegameinfo[savetodraw].lives == -42) if (savegameinfo[savetodraw].lives == -42)
V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "NEW GAME"); V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "NEW GAME");
else if (savegameinfo[savetodraw].lives == -666) else if (savegameinfo[savetodraw].lives == -666)
V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "CAN'T LOAD!"); {
if (savegameinfo[savetodraw].continuescore == -62)
{
V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "ADDON NOT LOADED");
V_DrawRightAlignedThinString(x + 79, y-10, V_REDMAP, savegameinfo[savetodraw].skinname);
}
else
{
V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "CAN'T LOAD!");
}
}
else if (savegameinfo[savetodraw].gamemap & 8192) else if (savegameinfo[savetodraw].gamemap & 8192)
V_DrawRightAlignedThinString(x + 79, y, V_GREENMAP, "CLEAR!"); V_DrawRightAlignedThinString(x + 79, y, V_GREENMAP, "CLEAR!");
else else
@ -8665,6 +8921,7 @@ static void M_LoadSelect(INT32 choice)
} }
#define VERSIONSIZE 16 #define VERSIONSIZE 16
#define MISSING { savegameinfo[slot].continuescore = -62; savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; }
#define BADSAVE { savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; } #define BADSAVE { savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; }
#define CHECKPOS if (sav_p >= end_p) BADSAVE #define CHECKPOS if (sav_p >= end_p) BADSAVE
// Reads the save file to list lives, level, player, etc. // Reads the save file to list lives, level, player, etc.
@ -8761,10 +9018,11 @@ static void M_ReadSavegameInfo(UINT32 slot)
CHECKPOS CHECKPOS
READSTRINGN(sav_p, ourSkinName, SKINNAMESIZE); READSTRINGN(sav_p, ourSkinName, SKINNAMESIZE);
savegameinfo[slot].skinnum = R_SkinAvailable(ourSkinName); savegameinfo[slot].skinnum = R_SkinAvailable(ourSkinName);
STRBUFCPY(savegameinfo[slot].skinname, ourSkinName);
if (savegameinfo[slot].skinnum >= numskins if (savegameinfo[slot].skinnum >= numskins
|| !R_SkinUsable(-1, savegameinfo[slot].skinnum)) || !R_SkinUsable(-1, savegameinfo[slot].skinnum))
BADSAVE MISSING
CHECKPOS CHECKPOS
READSTRINGN(sav_p, botSkinName, SKINNAMESIZE); READSTRINGN(sav_p, botSkinName, SKINNAMESIZE);
@ -8772,7 +9030,7 @@ static void M_ReadSavegameInfo(UINT32 slot)
if (savegameinfo[slot].botskin-1 >= numskins if (savegameinfo[slot].botskin-1 >= numskins
|| !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) || !R_SkinUsable(-1, savegameinfo[slot].botskin-1))
BADSAVE MISSING
} }
CHECKPOS CHECKPOS
@ -8817,6 +9075,7 @@ static void M_ReadSavegameInfo(UINT32 slot)
} }
#undef CHECKPOS #undef CHECKPOS
#undef BADSAVE #undef BADSAVE
#undef MISSING
// //
// M_ReadSaveStrings // M_ReadSaveStrings
@ -11864,8 +12123,7 @@ static void M_HandleConnectIP(INT32 choice)
if ( ctrldown ) { if ( ctrldown ) {
switch (choice) { switch (choice) {
case 'v': case 'v': // ctrl+v, pasting
case 'V': // ctrl+v, pasting
{ {
const char *paste = I_ClipboardPaste(); const char *paste = I_ClipboardPaste();
@ -11878,8 +12136,7 @@ static void M_HandleConnectIP(INT32 choice)
break; break;
} }
case KEY_INS: case KEY_INS:
case 'c': case 'c': // ctrl+c, ctrl+insert, copying
case 'C': // ctrl+c, ctrl+insert, copying
if (l != 0) // Don't replace the clipboard without any text if (l != 0) // Don't replace the clipboard without any text
{ {
I_ClipboardCopy(setupm_ip, l); I_ClipboardCopy(setupm_ip, l);
@ -11887,8 +12144,7 @@ static void M_HandleConnectIP(INT32 choice)
} }
break; break;
case 'x': case 'x': // ctrl+x, cutting
case 'X': // ctrl+x, cutting
if (l != 0) // Don't replace the clipboard without any text if (l != 0) // Don't replace the clipboard without any text
{ {
I_ClipboardCopy(setupm_ip, l); I_ClipboardCopy(setupm_ip, l);
@ -11944,15 +12200,6 @@ static void M_HandleConnectIP(INT32 choice)
setupm_ip[l] = (char)choice; setupm_ip[l] = (char)choice;
setupm_ip[l+1] = 0; setupm_ip[l+1] = 0;
} }
else if (choice >= 199 && choice <= 211 && choice != 202 && choice != 206) //numpad too!
{
char keypad_translation[] = {'7','8','9','-','4','5','6','+','1','2','3','0','.'};
choice = keypad_translation[choice - 199];
S_StartSound(NULL,sfx_menu1); // Tails
setupm_ip[l] = (char)choice;
setupm_ip[l+1] = 0;
}
break; break;
} }

View file

@ -3,7 +3,7 @@
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -176,6 +176,7 @@ typedef struct
extern menupres_t menupres[NUMMENUTYPES]; extern menupres_t menupres[NUMMENUTYPES];
extern UINT32 prevMenuId; extern UINT32 prevMenuId;
extern UINT32 activeMenuId; extern UINT32 activeMenuId;
extern tic_t shieldprompt_timer; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove
void M_InitMenuPresTables(void); void M_InitMenuPresTables(void);
UINT8 M_GetYoungestChildMenu(void); UINT8 M_GetYoungestChildMenu(void);
@ -421,6 +422,7 @@ typedef struct
{ {
char levelname[32]; char levelname[32];
UINT8 skinnum; UINT8 skinnum;
char skinname [SKINNAMESIZE+1];
UINT8 botskin; UINT8 botskin;
UINT8 numemeralds; UINT8 numemeralds;
UINT8 numgameovers; UINT8 numgameovers;

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -560,6 +560,11 @@ void M_FirstLoadConfig(void)
COM_BufInsertText(va("exec \"%s\"\n", configfile)); COM_BufInsertText(va("exec \"%s\"\n", configfile));
// no COM_BufExecute() needed; that does it right away // no COM_BufExecute() needed; that does it right away
// For configs loaded at startup only, check for pre-Shield-button configs // TODO: 2.3: Remove
if (GETMAJOREXECVERSION(cv_execversion.value) < 55 // Pre-v2.2.14 configs
&& cv_execversion.value != 25) // Make sure that the config exists, too
shieldprompt_timer = 1;
// don't filter anymore vars and don't let this convsvar be changed // don't filter anymore vars and don't let this convsvar be changed
COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, EXECVERSION)); COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, EXECVERSION));
CV_ToggleExecVersion(false); CV_ToggleExecVersion(false);

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -453,7 +453,7 @@ static int PS_DrawPerfRows(int x, int y, int color, perfstatrow_t *rows)
return draw_y; return draw_y;
} }
static void PS_UpdateMetricHistory(ps_metric_t *metric, boolean time_metric, boolean frame_metric, boolean set_user) static void PS_UpdateMetricHistory(ps_metric_t *metric, boolean time_metric, boolean frame_metric)
{ {
int index = frame_metric ? ps_frame_index : ps_tick_index; int index = frame_metric ? ps_frame_index : ps_tick_index;
@ -461,7 +461,7 @@ static void PS_UpdateMetricHistory(ps_metric_t *metric, boolean time_metric, boo
{ {
// allocate history table // allocate history table
int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32);
void** memory_user = set_user ? &metric->history : NULL; void** memory_user = &metric->history;
metric->history = Z_Calloc(value_size * cv_ps_samplesize.value, PU_PERFSTATS, metric->history = Z_Calloc(value_size * cv_ps_samplesize.value, PU_PERFSTATS,
memory_user); memory_user);
@ -491,7 +491,7 @@ static void PS_UpdateRowHistories(perfstatrow_t *rows, boolean frame_metric)
for (row = rows; row->lores_label; row++) for (row = rows; row->lores_label; row++)
{ {
if (PS_IsRowValid(row)) if (PS_IsRowValid(row))
PS_UpdateMetricHistory(row->metric, !!(row->flags & PS_TIME), frame_metric, true); PS_UpdateMetricHistory(row->metric, !!(row->flags & PS_TIME), frame_metric);
} }
} }
@ -584,7 +584,7 @@ static void PS_CountThinkers(void)
for (thinker = thlist[i].next; thinker != &thlist[i]; thinker = thinker->next) for (thinker = thlist[i].next; thinker != &thlist[i]; thinker = thinker->next)
{ {
ps_thinkercount.value.i++; ps_thinkercount.value.i++;
if (thinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (thinker->removing)
ps_removecount.value.i++; ps_removecount.value.i++;
else if (i == THINK_POLYOBJ) else if (i == THINK_POLYOBJ)
ps_polythcount.value.i++; ps_polythcount.value.i++;
@ -649,17 +649,17 @@ void PS_UpdateTickStats(void)
if (cv_perfstats.value == 3) if (cv_perfstats.value == 3)
{ {
for (i = 0; i < thinkframe_hooks_length; i++) for (i = 0; i < thinkframe_hooks_length; i++)
PS_UpdateMetricHistory(&thinkframe_hooks[i].time_taken, true, false, false); PS_UpdateMetricHistory(&thinkframe_hooks[i].time_taken, true, false);
} }
else if (cv_perfstats.value == 4) else if (cv_perfstats.value == 4)
{ {
for (i = 0; i < prethinkframe_hooks_length; i++) for (i = 0; i < prethinkframe_hooks_length; i++)
PS_UpdateMetricHistory(&prethinkframe_hooks[i].time_taken, true, false, false); PS_UpdateMetricHistory(&prethinkframe_hooks[i].time_taken, true, false);
} }
else if (cv_perfstats.value == 5) else if (cv_perfstats.value == 5)
{ {
for (i = 0; i < postthinkframe_hooks_length; i++) for (i = 0; i < postthinkframe_hooks_length; i++)
PS_UpdateMetricHistory(&postthinkframe_hooks[i].time_taken, true, false, false); PS_UpdateMetricHistory(&postthinkframe_hooks[i].time_taken, true, false);
} }
} }
if (cv_perfstats.value) if (cv_perfstats.value)

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2013-2023 by Sonic Team Junior. // Copyright (C) 2013-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -1,6 +1,6 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2013-2023 by Sonic Team Junior. // Copyright (C) 2013-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -546,6 +546,7 @@ static void AbortConnection(void)
{ {
Snake_Free(&snake); Snake_Free(&snake);
CURLAbortFile();
D_QuitNetGame(); D_QuitNetGame();
CL_Reset(); CL_Reset();
D_StartTitle(); D_StartTitle();
@ -1062,10 +1063,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
} }
} }
// Rusty TODO: multithread
if (filedownload.http_running)
CURLGetFile();
if (waitmore) if (waitmore)
break; // exit the case break; // exit the case

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -114,6 +114,7 @@ static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0,
consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL);
consvar_t cv_idletime = CVAR_INIT ("idletime", "0", CV_SAVE, CV_Unsigned, NULL); consvar_t cv_idletime = CVAR_INIT ("idletime", "0", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_idlespectate = CVAR_INIT ("idlespectate", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_dedicatedidletime = CVAR_INIT ("dedicatedidletime", "10", CV_SAVE, CV_Unsigned, NULL); consvar_t cv_dedicatedidletime = CVAR_INIT ("dedicatedidletime", "10", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_httpsource = CVAR_INIT ("http_source", "", CV_SAVE, NULL, NULL); consvar_t cv_httpsource = CVAR_INIT ("http_source", "", CV_SAVE, NULL, NULL);
@ -1360,19 +1361,33 @@ static void IdleUpdate(void)
if (!server || !netgame) if (!server || !netgame)
return; return;
for (i = 1; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (cv_idletime.value && playeringame[i] && playernode[i] != UINT8_MAX && !players[i].quittime && !players[i].spectator && !players[i].bot && !IsPlayerAdmin(i) && i != serverplayer && gamestate == GS_LEVEL) if (playeringame[i] && playernode[i] != UINT8_MAX && !players[i].quittime && !players[i].spectator && !players[i].bot && gamestate == GS_LEVEL)
{ {
if (players[i].cmd.forwardmove || players[i].cmd.sidemove || players[i].cmd.buttons) if (players[i].cmd.forwardmove || players[i].cmd.sidemove || players[i].cmd.buttons)
players[i].lastinputtime = 0; players[i].lastinputtime = 0;
else else
players[i].lastinputtime++; players[i].lastinputtime++;
if (players[i].lastinputtime > (tic_t)cv_idletime.value * TICRATE * 60) if (cv_idletime.value && !IsPlayerAdmin(i) && i != serverplayer && !(players[i].pflags & PF_FINISHED) && players[i].lastinputtime > (tic_t)cv_idletime.value * TICRATE * 60)
{ {
players[i].lastinputtime = 0; players[i].lastinputtime = 0;
SendKick(i, KICK_MSG_IDLE | KICK_MSG_KEEP_BODY); if (cv_idlespectate.value && G_GametypeHasSpectators())
{
changeteam_union NetPacket;
UINT16 usvalue;
NetPacket.value.l = NetPacket.value.b = 0;
NetPacket.packet.newteam = 0;
NetPacket.packet.playernum = i;
NetPacket.packet.verification = true; // This signals that it's a server change
usvalue = SHORT(NetPacket.value.l|NetPacket.value.b);
SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue));
}
else
{
SendKick(i, KICK_MSG_IDLE | KICK_MSG_KEEP_BODY);
}
} }
} }
else else
@ -1399,6 +1414,83 @@ static void IdleUpdate(void)
} }
} }
static void DedicatedIdleUpdate(INT32 *realtics)
{
const tic_t dedicatedidletime = cv_dedicatedidletime.value * TICRATE;
static tic_t dedicatedidletimeprev = 0;
static tic_t dedicatedidle = 0;
if (!server || !dedicated || gamestate != GS_LEVEL)
return;
if (dedicatedidletime > 0)
{
INT32 i;
boolean empty = true;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
{
empty = false;
break;
}
if (empty)
{
if (leveltime == 2)
{
// On next tick...
dedicatedidle = dedicatedidletime - 1;
}
else if (dedicatedidle >= dedicatedidletime)
{
if (D_GetExistingTextcmd(gametic, 0) || D_GetExistingTextcmd(gametic + 1, 0))
{
CONS_Printf("DEDICATED: Awakening from idle (Netxcmd detected...)\n");
dedicatedidle = 0;
}
else
{
(*realtics) = 0;
}
}
else
{
dedicatedidle += (*realtics);
if (dedicatedidle >= dedicatedidletime)
{
const char *idlereason = "at round start";
if (leveltime > 3)
idlereason = va("for %d seconds", dedicatedidle / TICRATE);
CONS_Printf("DEDICATED: No players %s, idling...\n", idlereason);
(*realtics) = 0;
dedicatedidle = dedicatedidletime;
}
}
}
else
{
if (dedicatedidle >= dedicatedidletime)
{
CONS_Printf("DEDICATED: Awakening from idle (Player detected...)\n");
}
dedicatedidle = 0;
}
}
else
{
if (dedicatedidletimeprev > 0 && dedicatedidle >= dedicatedidletimeprev)
{
CONS_Printf("DEDICATED: Awakening from idle (Idle disabled...)\n");
}
dedicatedidle = 0;
}
dedicatedidletimeprev = dedicatedidletime;
}
// Handle timeouts to prevent definitive freezes from happenning // Handle timeouts to prevent definitive freezes from happenning
static void HandleNodeTimeouts(void) static void HandleNodeTimeouts(void)
{ {
@ -1475,69 +1567,7 @@ void NetUpdate(void)
realtics = 5; realtics = 5;
} }
if (server && dedicated && gamestate == GS_LEVEL) DedicatedIdleUpdate(&realtics);
{
const tic_t dedicatedidletime = cv_dedicatedidletime.value * TICRATE;
static tic_t dedicatedidletimeprev = 0;
static tic_t dedicatedidle = 0;
if (dedicatedidletime > 0)
{
INT32 i;
for (i = 1; i < MAXNETNODES; ++i)
if (netnodes[i].ingame)
{
if (dedicatedidle >= dedicatedidletime)
{
CONS_Printf("DEDICATED: Awakening from idle (Node %d detected...)\n", i);
dedicatedidle = 0;
}
break;
}
if (i == MAXNETNODES)
{
if (leveltime == 2)
{
// On next tick...
dedicatedidle = dedicatedidletime-1;
}
else if (dedicatedidle >= dedicatedidletime)
{
if (D_GetExistingTextcmd(gametic, 0) || D_GetExistingTextcmd(gametic+1, 0))
{
CONS_Printf("DEDICATED: Awakening from idle (Netxcmd detected...)\n");
dedicatedidle = 0;
}
else
{
realtics = 0;
}
}
else if ((dedicatedidle += realtics) >= dedicatedidletime)
{
const char *idlereason = "at round start";
if (leveltime > 3)
idlereason = va("for %d seconds", dedicatedidle/TICRATE);
CONS_Printf("DEDICATED: No nodes %s, idling...\n", idlereason);
realtics = 0;
dedicatedidle = dedicatedidletime;
}
}
}
else
{
if (dedicatedidletimeprev > 0 && dedicatedidle >= dedicatedidletimeprev)
{
CONS_Printf("DEDICATED: Awakening from idle (Idle disabled...)\n");
}
dedicatedidle = 0;
}
dedicatedidletimeprev = dedicatedidletime;
}
gametime = nowtime; gametime = nowtime;
@ -1784,7 +1814,7 @@ INT16 Consistancy(void)
{ {
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->removing)
continue; continue;
mo = (mobj_t *)th; mo = (mobj_t *)th;

View file

@ -73,7 +73,7 @@ extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping; extern tic_t servermaxping;
extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed, cv_idletime, cv_dedicatedidletime; extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed, cv_idletime, cv_idlespectate, cv_dedicatedidletime;
extern consvar_t cv_httpsource; extern consvar_t cv_httpsource;
// Used in d_net, the only dependence // Used in d_net, the only dependence

View file

@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
@ -62,16 +62,11 @@ static doomdata_t reboundstore[MAXREBOUND];
static INT16 reboundsize[MAXREBOUND]; static INT16 reboundsize[MAXREBOUND];
static INT32 rebound_head, rebound_tail; static INT32 rebound_head, rebound_tail;
/// \brief bandwith of netgame
INT32 net_bandwidth;
/// \brief max length per packet /// \brief max length per packet
INT16 hardware_MAXPACKETLENGTH; INT16 hardware_MAXPACKETLENGTH;
boolean (*I_NetGet)(void) = NULL; boolean (*I_NetGet)(void) = NULL;
void (*I_NetSend)(void) = NULL; void (*I_NetSend)(void) = NULL;
boolean (*I_NetCanSend)(void) = NULL;
boolean (*I_NetCanGet)(void) = NULL;
void (*I_NetCloseSocket)(void) = NULL; void (*I_NetCloseSocket)(void) = NULL;
void (*I_NetFreeNodenum)(INT32 nodenum) = NULL; void (*I_NetFreeNodenum)(INT32 nodenum) = NULL;
SINT8 (*I_NetMakeNodewPort)(const char *address, const char* port) = NULL; SINT8 (*I_NetMakeNodewPort)(const char *address, const char* port) = NULL;
@ -996,15 +991,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
netbuffer->ackreturn = 0; netbuffer->ackreturn = 0;
if (reliable) if (reliable)
{ {
if (I_NetCanSend && !I_NetCanSend()) if (!GetFreeAcknum(&netbuffer->ack, false))
{
if (netbuffer->packettype < PT_CANFAIL)
GetFreeAcknum(&netbuffer->ack, true);
DEBFILE("HSendPacket: Out of bandwidth\n");
return false;
}
else if (!GetFreeAcknum(&netbuffer->ack, false))
return false; return false;
} }
else else
@ -1156,7 +1143,7 @@ static void Internal_FreeNodenum(INT32 nodenum)
char *I_NetSplitAddress(char *host, char **port) char *I_NetSplitAddress(char *host, char **port)
{ {
boolean v4 = (strchr(host, '.') != NULL); boolean v4 = (host[0] != '[');
host = strtok(host, v4 ? ":" : "[]"); host = strtok(host, v4 ? ":" : "[]");
@ -1189,10 +1176,7 @@ void D_SetDoomcom(void)
{ {
if (doomcom) return; if (doomcom) return;
doomcom = Z_Calloc(sizeof (doomcom_t), PU_STATIC, NULL); doomcom = Z_Calloc(sizeof (doomcom_t), PU_STATIC, NULL);
doomcom->id = DOOMCOM_ID;
doomcom->numslots = doomcom->numnodes = 1; doomcom->numslots = doomcom->numnodes = 1;
doomcom->gametype = 0;
doomcom->consoleplayer = 0;
doomcom->extratics = 0; doomcom->extratics = 0;
} }
@ -1211,13 +1195,11 @@ boolean D_CheckNetGame(void)
I_NetGet = Internal_Get; I_NetGet = Internal_Get;
I_NetSend = Internal_Send; I_NetSend = Internal_Send;
I_NetCanSend = NULL;
I_NetCloseSocket = NULL; I_NetCloseSocket = NULL;
I_NetFreeNodenum = Internal_FreeNodenum; I_NetFreeNodenum = Internal_FreeNodenum;
I_NetMakeNodewPort = NULL; I_NetMakeNodewPort = NULL;
hardware_MAXPACKETLENGTH = MAXPACKETLENGTH; hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
net_bandwidth = 30000;
// I_InitNetwork sets doomcom and netgame // I_InitNetwork sets doomcom and netgame
// check and initialize the network driver // check and initialize the network driver
multiplayer = false; multiplayer = false;
@ -1237,7 +1219,6 @@ boolean D_CheckNetGame(void)
server = true; // WTF? server always true??? server = true; // WTF? server always true???
// no! The deault mode is server. Client is set elsewhere // no! The deault mode is server. Client is set elsewhere
// when the client executes connect command. // when the client executes connect command.
doomcom->ticdup = 1;
if (M_CheckParm("-extratic")) if (M_CheckParm("-extratic"))
{ {
@ -1248,21 +1229,6 @@ boolean D_CheckNetGame(void)
CONS_Printf(M_GetText("Set extratics to %d\n"), doomcom->extratics); CONS_Printf(M_GetText("Set extratics to %d\n"), doomcom->extratics);
} }
if (M_CheckParm("-bandwidth"))
{
if (M_IsNextParm())
{
net_bandwidth = atoi(M_GetNextParm());
if (net_bandwidth < 1000)
net_bandwidth = 1000;
if (net_bandwidth > 100000)
hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
CONS_Printf(M_GetText("Network bandwidth set to %d\n"), net_bandwidth);
}
else
I_Error("usage: -bandwidth <byte_per_sec>");
}
software_MAXPACKETLENGTH = hardware_MAXPACKETLENGTH; software_MAXPACKETLENGTH = hardware_MAXPACKETLENGTH;
if (M_CheckParm("-packetsize")) if (M_CheckParm("-packetsize"))
{ {
@ -1282,8 +1248,6 @@ boolean D_CheckNetGame(void)
if (netgame) if (netgame)
multiplayer = true; multiplayer = true;
if (doomcom->id != DOOMCOM_ID)
I_Error("Doomcom buffer invalid!");
if (doomcom->numnodes > MAXNETNODES) if (doomcom->numnodes > MAXNETNODES)
I_Error("Too many nodes (%d), max:%d", doomcom->numnodes, MAXNETNODES); I_Error("Too many nodes (%d), max:%d", doomcom->numnodes, MAXNETNODES);
@ -1293,7 +1257,7 @@ boolean D_CheckNetGame(void)
if (M_CheckParm("-debugfile")) if (M_CheckParm("-debugfile"))
{ {
char filename[21]; char filename[21];
INT32 k = doomcom->consoleplayer - 1; INT32 k = consoleplayer - 1;
if (M_IsNextParm()) if (M_IsNextParm())
k = atoi(M_GetNextParm()) - 1; k = atoi(M_GetNextParm()) - 1;
while (!debugfile && k < MAXPLAYERS) while (!debugfile && k < MAXPLAYERS)
@ -1400,7 +1364,6 @@ void D_CloseConnection(void)
I_NetGet = Internal_Get; I_NetGet = Internal_Get;
I_NetSend = Internal_Send; I_NetSend = Internal_Send;
I_NetCanSend = NULL;
I_NetCloseSocket = NULL; I_NetCloseSocket = NULL;
I_NetFreeNodenum = Internal_FreeNodenum; I_NetFreeNodenum = Internal_FreeNodenum;
I_NetMakeNodewPort = NULL; I_NetMakeNodewPort = NULL;

View file

@ -391,7 +391,7 @@ static CV_PossibleValue_t perfstats_cons_t[] = {
consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", CV_CALL, perfstats_cons_t, PS_PerfStats_OnChange); consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", CV_CALL, perfstats_cons_t, PS_PerfStats_OnChange);
static CV_PossibleValue_t ps_samplesize_cons_t[] = { static CV_PossibleValue_t ps_samplesize_cons_t[] = {
{1, "MIN"}, {1000, "MAX"}, {0, NULL}}; {1, "MIN"}, {1000, "MAX"}, {0, NULL}};
consvar_t cv_ps_samplesize = CVAR_INIT ("ps_samplesize", "1", CV_CALL, ps_samplesize_cons_t, PS_SampleSize_OnChange); consvar_t cv_ps_samplesize = CVAR_INIT ("ps_samplesize", "175", CV_CALL, ps_samplesize_cons_t, PS_SampleSize_OnChange);
static CV_PossibleValue_t ps_descriptor_cons_t[] = { static CV_PossibleValue_t ps_descriptor_cons_t[] = {
{1, "Average"}, {2, "SD"}, {3, "Minimum"}, {4, "Maximum"}, {0, NULL}}; {1, "Average"}, {2, "SD"}, {3, "Minimum"}, {4, "Maximum"}, {0, NULL}};
consvar_t cv_ps_descriptor = CVAR_INIT ("ps_descriptor", "Average", 0, ps_descriptor_cons_t, NULL); consvar_t cv_ps_descriptor = CVAR_INIT ("ps_descriptor", "Average", 0, ps_descriptor_cons_t, NULL);
@ -620,6 +620,7 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_blamecfail); CV_RegisterVar(&cv_blamecfail);
CV_RegisterVar(&cv_dedicatedidletime); CV_RegisterVar(&cv_dedicatedidletime);
CV_RegisterVar(&cv_idletime); CV_RegisterVar(&cv_idletime);
CV_RegisterVar(&cv_idlespectate);
CV_RegisterVar(&cv_httpsource); CV_RegisterVar(&cv_httpsource);
COM_AddCommand("ping", Command_Ping_f, COM_LUA); COM_AddCommand("ping", Command_Ping_f, COM_LUA);
@ -2510,11 +2511,11 @@ static void MutePlayer(boolean mute)
if (COM_Argc() < 2) if (COM_Argc() < 2)
{ {
CONS_Printf(M_GetText("muteplayer <playernum>: mute a player\n")); CONS_Printf(M_GetText("muteplayer <playername/playernum>: mute a player\n"));
return; return;
} }
data[0] = atoi(COM_Argv(1)); data[0] = nametonum(COM_Argv(1));
if (data[0] >= MAXPLAYERS || !playeringame[data[0]]) if (data[0] >= MAXPLAYERS || !playeringame[data[0]])
{ {
CONS_Alert(CONS_NOTICE, M_GetText("There is no player %u!\n"), (unsigned int)data[0]); CONS_Alert(CONS_NOTICE, M_GetText("There is no player %u!\n"), (unsigned int)data[0]);
@ -2603,11 +2604,11 @@ static void Command_ServerTeamChange_f(void)
if (COM_Argc() < 3) if (COM_Argc() < 3)
{ {
if (G_TagGametype()) if (G_TagGametype())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "it, notit, playing, or spectator"); CONS_Printf(M_GetText("serverchangeteam <playername/playernum> <team>: switch player to a new team (%s)\n"), "it, notit, playing, or spectator");
else if (G_GametypeHasTeams()) else if (G_GametypeHasTeams())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "red, blue or spectator"); CONS_Printf(M_GetText("serverchangeteam <playername/playernum> <team>: switch player to a new team (%s)\n"), "red, blue or spectator");
else if (G_GametypeHasSpectators()) else if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "spectator or playing"); CONS_Printf(M_GetText("serverchangeteam <playername/playernum> <team>: switch player to a new team (%s)\n"), "spectator or playing");
else else
CONS_Alert(CONS_NOTICE, M_GetText("This command cannot be used in this gametype.\n")); CONS_Alert(CONS_NOTICE, M_GetText("This command cannot be used in this gametype.\n"));
return; return;
@ -2655,19 +2656,19 @@ static void Command_ServerTeamChange_f(void)
if (error) if (error)
{ {
if (G_TagGametype()) if (G_TagGametype())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "it, notit, playing, or spectator"); CONS_Printf(M_GetText("serverchangeteam <playername/playernum> <team>: switch player to a new team (%s)\n"), "it, notit, playing, or spectator");
else if (G_GametypeHasTeams()) else if (G_GametypeHasTeams())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "red, blue or spectator"); CONS_Printf(M_GetText("serverchangeteam <playername/playernum> <team>: switch player to a new team (%s)\n"), "red, blue or spectator");
else if (G_GametypeHasSpectators()) else if (G_GametypeHasSpectators())
CONS_Printf(M_GetText("serverchangeteam <playernum> <team>: switch player to a new team (%s)\n"), "spectator or playing"); CONS_Printf(M_GetText("serverchangeteam <playername/playernum> <team>: switch player to a new team (%s)\n"), "spectator or playing");
return; return;
} }
NetPacket.packet.playernum = atoi(COM_Argv(1)); NetPacket.packet.playernum = nametonum(COM_Argv(1));
if (!playeringame[NetPacket.packet.playernum]) if (NetPacket.packet.playernum == -1 || !playeringame[NetPacket.packet.playernum])
{ {
CONS_Alert(CONS_NOTICE, M_GetText("There is no player %d!\n"), NetPacket.packet.playernum); CONS_Alert(CONS_NOTICE, M_GetText("There is no player %s!\n"), COM_Argv(1));
return; return;
} }
@ -3106,13 +3107,16 @@ static void Command_Verify_f(void)
if (COM_Argc() != 2) if (COM_Argc() != 2)
{ {
CONS_Printf(M_GetText("promote <playernum>: give admin privileges to a player\n")); CONS_Printf(M_GetText("promote <playername/playernum>: give admin privileges to a player\n"));
return; return;
} }
strlcpy(buf, COM_Argv(1), sizeof (buf)); playernum = nametonum(COM_Argv(1));
if (playernum == -1)
playernum = atoi(buf); {
CONS_Alert(CONS_NOTICE, M_GetText("There is no player %s!\n"), COM_Argv(1));
return;
}
temp = buf; temp = buf;
@ -3156,13 +3160,16 @@ static void Command_RemoveAdmin_f(void)
if (COM_Argc() != 2) if (COM_Argc() != 2)
{ {
CONS_Printf(M_GetText("demote <playernum>: remove admin privileges from a player\n")); CONS_Printf(M_GetText("demote <playername/playernum>: remove admin privileges from a player\n"));
return; return;
} }
strlcpy(buf, COM_Argv(1), sizeof(buf)); playernum = nametonum(COM_Argv(1));
if (playernum == -1)
playernum = atoi(buf); {
CONS_Alert(CONS_NOTICE, M_GetText("There is no player %s!\n"), COM_Argv(1));
return;
}
temp = buf; temp = buf;
@ -4792,12 +4799,11 @@ static void Command_Togglemodified_f(void)
modifiedgame = !modifiedgame; modifiedgame = !modifiedgame;
} }
extern UINT8 *save_p;
static void Command_Archivetest_f(void) static void Command_Archivetest_f(void)
{ {
UINT8 *buf;
UINT32 i, wrote; UINT32 i, wrote;
thinker_t *th; thinker_t *th;
save_t savebuffer;
if (gamestate != GS_LEVEL) if (gamestate != GS_LEVEL)
{ {
CONS_Printf("This command only works in-game, you dummy.\n"); CONS_Printf("This command only works in-game, you dummy.\n");
@ -4811,28 +4817,29 @@ static void Command_Archivetest_f(void)
((mobj_t *)th)->mobjnum = i++; ((mobj_t *)th)->mobjnum = i++;
// allocate buffer // allocate buffer
buf = save_p = ZZ_Alloc(1024); savebuffer.size = 1024;
savebuffer.buf = malloc(savebuffer.size);
savebuffer.pos = 0;
// test archive // test archive
CONS_Printf("LUA_Archive...\n"); CONS_Printf("LUA_Archive...\n");
LUA_Archive(); LUA_Archive(&savebuffer);
WRITEUINT8(save_p, 0x7F); P_WriteUINT8(&savebuffer, 0x7F);
wrote = (UINT32)(save_p-buf); wrote = savebuffer.pos;
// clear Lua state, so we can really see what happens! // clear Lua state, so we can really see what happens!
CONS_Printf("Clearing state!\n"); CONS_Printf("Clearing state!\n");
LUA_ClearExtVars(); LUA_ClearExtVars();
// test unarchive // test unarchive
save_p = buf;
CONS_Printf("LUA_UnArchive...\n"); CONS_Printf("LUA_UnArchive...\n");
LUA_UnArchive(); LUA_UnArchive(&savebuffer);
i = READUINT8(save_p); i = P_ReadUINT8(&savebuffer);
if (i != 0x7F || wrote != (UINT32)(save_p-buf)) if (i != 0x7F || wrote != (UINT32)(savebuffer.pos))
CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(save_p-buf)); CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(savebuffer.pos));
// free buffer // free buffer
Z_Free(buf); free(savebuffer.buf);
CONS_Printf("Done. No crash.\n"); CONS_Printf("Done. No crash.\n");
} }
#endif #endif
@ -4903,11 +4910,13 @@ static void Name2_OnChange(void)
static boolean Skin_CanChange(const char *valstr) static boolean Skin_CanChange(const char *valstr)
{ {
(void)valstr;
if (!Playing()) if (!Playing())
return true; // do whatever you want return true; // do whatever you want
// You already are that skin.
if (stricmp(skins[players[consoleplayer].skin]->name, valstr) == 0)
return false;
if (!(multiplayer || netgame)) // In single player. if (!(multiplayer || netgame)) // In single player.
return true; return true;
@ -4922,11 +4931,13 @@ static boolean Skin_CanChange(const char *valstr)
static boolean Skin2_CanChange(const char *valstr) static boolean Skin2_CanChange(const char *valstr)
{ {
(void)valstr;
if (!Playing() || !splitscreen) if (!Playing() || !splitscreen)
return true; // do whatever you want return true; // do whatever you want
// You already are that skin.
if (stricmp(skins[players[secondarydisplayplayer].skin]->name, valstr) == 0)
return false;
if (CanChangeSkin(secondarydisplayplayer) && !P_PlayerMoving(secondarydisplayplayer)) if (CanChangeSkin(secondarydisplayplayer) && !P_PlayerMoving(secondarydisplayplayer))
return true; return true;
else else

View file

@ -1,7 +1,7 @@
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.

View file

@ -95,6 +95,7 @@ static filetran_t transfer[MAXNETNODES];
INT32 fileneedednum; // Number of files needed to join the server INT32 fileneedednum; // Number of files needed to join the server
fileneeded_t *fileneeded; // List of needed files fileneeded_t *fileneeded; // List of needed files
static tic_t lasttimeackpacketsent = 0; static tic_t lasttimeackpacketsent = 0;
static I_mutex downloadmutex;
char downloaddir[512] = "DOWNLOAD"; char downloaddir[512] = "DOWNLOAD";
// For resuming failed downloads // For resuming failed downloads
@ -606,7 +607,7 @@ void AddLuaFileTransfer(const char *filename, const char *mode)
prevnext = &((*prevnext)->next); prevnext = &((*prevnext)->next);
// Allocate file transfer information and append it to the transfer list // Allocate file transfer information and append it to the transfer list
filetransfer = malloc(sizeof(luafiletransfer_t)); filetransfer = calloc(1, sizeof(luafiletransfer_t));
if (!filetransfer) if (!filetransfer)
I_Error("AddLuaFileTransfer: Out of memory\n"); I_Error("AddLuaFileTransfer: Out of memory\n");
*prevnext = filetransfer; *prevnext = filetransfer;
@ -1033,7 +1034,6 @@ void FileSendTicker(void)
netbuffer->packettype = PT_FILEFRAGMENT; netbuffer->packettype = PT_FILEFRAGMENT;
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
while (packetsent-- && filestosend != 0) while (packetsent-- && filestosend != 0)
{ {
for (i = currentnode, j = 0; j < MAXNETNODES; for (i = currentnode, j = 0; j < MAXNETNODES;
@ -1610,11 +1610,13 @@ boolean CURLPrepareFile(const char* url, int dfilenum)
I_Error("Attempted to download files in -nodownload mode"); I_Error("Attempted to download files in -nodownload mode");
#endif #endif
curl_global_init(CURL_GLOBAL_ALL); if (!multi_handle)
{
curl_global_init(CURL_GLOBAL_ALL);
multi_handle = curl_multi_init();
}
http_handle = curl_easy_init(); http_handle = curl_easy_init();
multi_handle = curl_multi_init();
if (http_handle && multi_handle) if (http_handle && multi_handle)
{ {
I_mkdir(downloaddir, 0755); I_mkdir(downloaddir, 0755);
@ -1673,6 +1675,8 @@ boolean CURLPrepareFile(const char* url, int dfilenum)
filedownload.current = dfilenum; filedownload.current = dfilenum;
filedownload.http_running = true; filedownload.http_running = true;
I_spawn_thread("http-download", (I_thread_fn)CURLGetFile, NULL);
return true; return true;
} }
@ -1681,103 +1685,119 @@ boolean CURLPrepareFile(const char* url, int dfilenum)
return false; return false;
} }
void CURLAbortFile(void)
{
filedownload.http_running = false;
// lock and unlock to wait for the download thread to exit
I_lock_mutex(&downloadmutex);
I_unlock_mutex(downloadmutex);
}
void CURLGetFile(void) void CURLGetFile(void)
{ {
I_lock_mutex(&downloadmutex);
CURLMcode mc; /* return code used by curl_multi_wait() */ CURLMcode mc; /* return code used by curl_multi_wait() */
CURLcode easyres; /* Return from easy interface */ CURLcode easyres; /* Return from easy interface */
int numfds;
CURLMsg *m; /* for picking up messages with the transfer status */ CURLMsg *m; /* for picking up messages with the transfer status */
CURL *e; CURL *e;
int msgs_left; /* how many messages are left */ int msgs_left; /* how many messages are left */
const char *easy_handle_error; const char *easy_handle_error;
boolean running = true;
if (curl_runninghandles) while (running && filedownload.http_running)
{ {
curl_multi_perform(multi_handle, &curl_runninghandles); if (curl_runninghandles)
/* wait for activity, timeout or "nothing" */
mc = curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds);
if (mc != CURLM_OK)
{ {
CONS_Alert(CONS_WARNING, "curl_multi_wait() failed, code %d.\n", mc); curl_multi_perform(multi_handle, &curl_runninghandles);
return;
}
curl_curfile->currentsize = curl_dlnow;
curl_curfile->totalsize = curl_dltotal;
}
/* See how the transfers went */ /* wait for activity, timeout or "nothing" */
while ((m = curl_multi_info_read(multi_handle, &msgs_left))) mc = curl_multi_wait(multi_handle, NULL, 0, 1000, NULL);
{
if (m && (m->msg == CURLMSG_DONE))
{
e = m->easy_handle;
easyres = m->data.result;
char *filename = Z_StrDup(curl_realname); if (mc != CURLM_OK)
nameonly(filename);
if (easyres != CURLE_OK)
{ {
long response_code = 0; CONS_Alert(CONS_WARNING, "curl_multi_wait() failed, code %d.\n", mc);
continue;
if (easyres == CURLE_HTTP_RETURNED_ERROR)
curl_easy_getinfo(e, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code == 404)
curl_curfile->failed = FDOWNLOAD_FAIL_NOTFOUND;
else
curl_curfile->failed = FDOWNLOAD_FAIL_OTHER;
easy_handle_error = (response_code) ? va("HTTP response code %ld", response_code) : curl_easy_strerror(easyres);
curl_curfile->status = FS_FALLBACK;
curl_curfile->currentsize = curl_origfilesize;
curl_curfile->totalsize = curl_origtotalfilesize;
filedownload.http_failed = true;
fclose(curl_curfile->file);
remove(curl_curfile->filename);
CONS_Alert(CONS_ERROR, M_GetText("Failed to download addon \"%s\" (%s)\n"), filename, easy_handle_error);
} }
else curl_curfile->currentsize = curl_dlnow;
curl_curfile->totalsize = curl_dltotal;
}
/* See how the transfers went */
while ((m = curl_multi_info_read(multi_handle, &msgs_left)))
{
if (m && (m->msg == CURLMSG_DONE))
{ {
fclose(curl_curfile->file); running = false;
e = m->easy_handle;
easyres = m->data.result;
CONS_Printf(M_GetText("Finished download of \"%s\"\n"), filename); char *filename = Z_StrDup(curl_realname);
nameonly(filename);
if (checkfilemd5(curl_curfile->filename, curl_curfile->md5sum) == FS_MD5SUMBAD) if (easyres != CURLE_OK)
{ {
CONS_Alert(CONS_WARNING, M_GetText("File \"%s\" does not match the version used by the server\n"), filename); long response_code = 0;
if (easyres == CURLE_HTTP_RETURNED_ERROR)
curl_easy_getinfo(e, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code == 404)
curl_curfile->failed = FDOWNLOAD_FAIL_NOTFOUND;
else
curl_curfile->failed = FDOWNLOAD_FAIL_OTHER;
easy_handle_error = (response_code) ? va("HTTP response code %ld", response_code) : curl_easy_strerror(easyres);
curl_curfile->status = FS_FALLBACK; curl_curfile->status = FS_FALLBACK;
curl_curfile->failed = FDOWNLOAD_FAIL_MD5SUMBAD; curl_curfile->currentsize = curl_origfilesize;
curl_curfile->totalsize = curl_origtotalfilesize;
filedownload.http_failed = true; filedownload.http_failed = true;
fclose(curl_curfile->file);
remove(curl_curfile->filename);
CONS_Alert(CONS_ERROR, M_GetText("Failed to download addon \"%s\" (%s)\n"), filename, easy_handle_error);
} }
else else
{ {
filedownload.completednum++; fclose(curl_curfile->file);
filedownload.completedsize += curl_curfile->totalsize;
curl_curfile->status = FS_FOUND; CONS_Printf(M_GetText("Finished download of \"%s\"\n"), filename);
if (checkfilemd5(curl_curfile->filename, curl_curfile->md5sum) == FS_MD5SUMBAD)
{
CONS_Alert(CONS_WARNING, M_GetText("File \"%s\" does not match the version used by the server\n"), filename);
curl_curfile->status = FS_FALLBACK;
curl_curfile->failed = FDOWNLOAD_FAIL_MD5SUMBAD;
filedownload.http_failed = true;
}
else
{
filedownload.completednum++;
filedownload.completedsize += curl_curfile->totalsize;
curl_curfile->status = FS_FOUND;
}
} }
Z_Free(filename);
curl_curfile->file = NULL;
filedownload.remaining--;
curl_multi_remove_handle(multi_handle, e);
curl_easy_cleanup(e);
if (!filedownload.remaining)
break;
} }
Z_Free(filename);
curl_curfile->file = NULL;
filedownload.http_running = false;
filedownload.remaining--;
curl_multi_remove_handle(multi_handle, e);
curl_easy_cleanup(e);
if (!filedownload.remaining)
break;
} }
} }
if (!filedownload.remaining) if (!filedownload.remaining || !filedownload.http_running)
{ {
curl_multi_cleanup(multi_handle); curl_multi_cleanup(multi_handle);
curl_global_cleanup(); curl_global_cleanup();
multi_handle = NULL;
} }
filedownload.http_running = false;
I_unlock_mutex(downloadmutex);
} }
HTTP_login * HTTP_login *

Some files were not shown because too many files have changed in this diff Show more