All changes present in QSS-R7, plus
md3 support quoth/etc bug fix strzone bug fix png/jpg replacement wall textures rewrote mdl rendering to always use arrays, relaxing vertex+tri limits. removed static ents limit fixed ambient_level not working at high framerates.
This commit is contained in:
parent
ad3aadb373
commit
d76ca606bf
|
@ -10,6 +10,9 @@ DO_USERDIRS=0
|
||||||
### Enable/Disable SDL2
|
### Enable/Disable SDL2
|
||||||
USE_SDL2=0
|
USE_SDL2=0
|
||||||
|
|
||||||
|
### Enable the use of zlib, for compressed pk3s.
|
||||||
|
USE_ZLIB=1
|
||||||
|
|
||||||
### Enable/Disable codecs for streaming music support
|
### Enable/Disable codecs for streaming music support
|
||||||
USE_CODEC_WAVE=1
|
USE_CODEC_WAVE=1
|
||||||
USE_CODEC_FLAC=0
|
USE_CODEC_FLAC=0
|
||||||
|
@ -176,7 +179,12 @@ ifeq ($(USE_CODEC_UMX),1)
|
||||||
CFLAGS+= -DUSE_CODEC_UMX
|
CFLAGS+= -DUSE_CODEC_UMX
|
||||||
endif
|
endif
|
||||||
|
|
||||||
COMMON_LIBS:= -lm -lGL
|
COMMON_LIBS:= -ldl -lm -lGL
|
||||||
|
|
||||||
|
ifeq ($(USE_ZLIB),1)
|
||||||
|
CFLAGS+= -DUSE_ZLIB
|
||||||
|
COMMON_LIBS+= -lz
|
||||||
|
endif
|
||||||
|
|
||||||
LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODECLIBS)
|
LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODECLIBS)
|
||||||
|
|
||||||
|
@ -210,7 +218,7 @@ MUSIC_OBJS:= bgmusic.o \
|
||||||
snd_mikmod.o \
|
snd_mikmod.o \
|
||||||
snd_xmp.o \
|
snd_xmp.o \
|
||||||
snd_umx.o
|
snd_umx.o
|
||||||
COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
|
COMOBJ_SND := snd_voip.o snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
|
||||||
SYSOBJ_SND := snd_sdl.o
|
SYSOBJ_SND := snd_sdl.o
|
||||||
SYSOBJ_CDA := cd_sdl.o
|
SYSOBJ_CDA := cd_sdl.o
|
||||||
SYSOBJ_INPUT := in_sdl.o
|
SYSOBJ_INPUT := in_sdl.o
|
||||||
|
@ -227,6 +235,7 @@ GLOBJS = \
|
||||||
gl_fog.o \
|
gl_fog.o \
|
||||||
gl_rmisc.o \
|
gl_rmisc.o \
|
||||||
r_part.o \
|
r_part.o \
|
||||||
|
r_part_fte.o \
|
||||||
r_world.o \
|
r_world.o \
|
||||||
gl_screen.o \
|
gl_screen.o \
|
||||||
gl_sky.o \
|
gl_sky.o \
|
||||||
|
@ -266,6 +275,7 @@ OBJS := strlcat.o \
|
||||||
wad.o \
|
wad.o \
|
||||||
cmd.o \
|
cmd.o \
|
||||||
common.o \
|
common.o \
|
||||||
|
fs_zip.o \
|
||||||
crc.o \
|
crc.o \
|
||||||
cvar.o \
|
cvar.o \
|
||||||
cfgfile.o \
|
cfgfile.o \
|
||||||
|
@ -273,6 +283,7 @@ OBJS := strlcat.o \
|
||||||
host_cmd.o \
|
host_cmd.o \
|
||||||
mathlib.o \
|
mathlib.o \
|
||||||
pr_cmds.o \
|
pr_cmds.o \
|
||||||
|
pr_ext.o \
|
||||||
pr_edict.o \
|
pr_edict.o \
|
||||||
pr_exec.o \
|
pr_exec.o \
|
||||||
sv_main.o \
|
sv_main.o \
|
||||||
|
|
|
@ -40,6 +40,7 @@ HOST_OS := $(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]')
|
||||||
MACH_TYPE= $(shell sh detect.sh arch)
|
MACH_TYPE= $(shell sh detect.sh arch)
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
|
USE_ZLIB?= 1
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# build variables
|
# build variables
|
||||||
|
@ -200,6 +201,11 @@ CFLAGS+= $(CODEC_INC)
|
||||||
|
|
||||||
COMMON_LIBS:= -Wl,-framework,IOKit -Wl,-framework,OpenGL
|
COMMON_LIBS:= -Wl,-framework,IOKit -Wl,-framework,OpenGL
|
||||||
|
|
||||||
|
ifeq ($(USE_ZLIB),1)
|
||||||
|
CFLAGS+= -DUSE_ZLIB
|
||||||
|
COMMON_LIBS+= `$(CC) -print-file-name=libz.a`
|
||||||
|
endif
|
||||||
|
|
||||||
LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
|
LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
@ -236,7 +242,7 @@ MUSIC_OBJS:= bgmusic.o \
|
||||||
snd_mikmod.o \
|
snd_mikmod.o \
|
||||||
snd_xmp.o \
|
snd_xmp.o \
|
||||||
snd_umx.o
|
snd_umx.o
|
||||||
COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
|
COMOBJ_SND := snd_voip.o snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
|
||||||
SYSOBJ_SND := snd_sdl.o
|
SYSOBJ_SND := snd_sdl.o
|
||||||
SYSOBJ_CDA := cd_sdl.o
|
SYSOBJ_CDA := cd_sdl.o
|
||||||
SYSOBJ_INPUT := in_sdl.o
|
SYSOBJ_INPUT := in_sdl.o
|
||||||
|
@ -253,6 +259,7 @@ GLOBJS = \
|
||||||
gl_fog.o \
|
gl_fog.o \
|
||||||
gl_rmisc.o \
|
gl_rmisc.o \
|
||||||
r_part.o \
|
r_part.o \
|
||||||
|
r_part_fte.o \
|
||||||
r_world.o \
|
r_world.o \
|
||||||
gl_screen.o \
|
gl_screen.o \
|
||||||
gl_sky.o \
|
gl_sky.o \
|
||||||
|
@ -292,6 +299,7 @@ OBJS := strlcat.o \
|
||||||
wad.o \
|
wad.o \
|
||||||
cmd.o \
|
cmd.o \
|
||||||
common.o \
|
common.o \
|
||||||
|
fs_zip.o \
|
||||||
crc.o \
|
crc.o \
|
||||||
cvar.o \
|
cvar.o \
|
||||||
cfgfile.o \
|
cfgfile.o \
|
||||||
|
@ -299,6 +307,7 @@ OBJS := strlcat.o \
|
||||||
host_cmd.o \
|
host_cmd.o \
|
||||||
mathlib.o \
|
mathlib.o \
|
||||||
pr_cmds.o \
|
pr_cmds.o \
|
||||||
|
pr_ext.o \
|
||||||
pr_edict.o \
|
pr_edict.o \
|
||||||
pr_exec.o \
|
pr_exec.o \
|
||||||
sv_main.o \
|
sv_main.o \
|
||||||
|
|
|
@ -33,7 +33,8 @@ check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/nu
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
WINSOCK2?= 0
|
WINSOCK2?= 1
|
||||||
|
USE_ZLIB?= 1
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# build variables
|
# build variables
|
||||||
|
@ -48,7 +49,7 @@ STRIP = strip
|
||||||
#CPUFLAGS= -mtune=i686
|
#CPUFLAGS= -mtune=i686
|
||||||
#CPUFLAGS= -march=pentium4
|
#CPUFLAGS= -march=pentium4
|
||||||
CPUFLAGS=
|
CPUFLAGS=
|
||||||
LDFLAGS = -m32 -mwindows
|
LDFLAGS = -m32 -mwindows -Wl,--large-address-aware
|
||||||
DFLAGS ?=
|
DFLAGS ?=
|
||||||
CFLAGS ?= -m32 -Wall -Wno-trigraphs
|
CFLAGS ?= -m32 -Wall -Wno-trigraphs
|
||||||
CFLAGS += $(CPUFLAGS)
|
CFLAGS += $(CPUFLAGS)
|
||||||
|
@ -166,6 +167,11 @@ CFLAGS+= $(CODEC_INC)
|
||||||
|
|
||||||
COMMON_LIBS:= -lm -lopengl32 -lwinmm
|
COMMON_LIBS:= -lm -lopengl32 -lwinmm
|
||||||
|
|
||||||
|
ifeq ($(USE_ZLIB),1)
|
||||||
|
CFLAGS+= -DUSE_ZLIB
|
||||||
|
COMMON_LIBS+= `$(CC) -print-file-name=libz.a`
|
||||||
|
endif
|
||||||
|
|
||||||
LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
|
LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
@ -200,7 +206,7 @@ MUSIC_OBJS:= bgmusic.o \
|
||||||
snd_mikmod.o \
|
snd_mikmod.o \
|
||||||
snd_xmp.o \
|
snd_xmp.o \
|
||||||
snd_umx.o
|
snd_umx.o
|
||||||
COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
|
COMOBJ_SND := snd_voip.o snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
|
||||||
SYSOBJ_SND := snd_sdl.o
|
SYSOBJ_SND := snd_sdl.o
|
||||||
SYSOBJ_CDA := cd_sdl.o
|
SYSOBJ_CDA := cd_sdl.o
|
||||||
SYSOBJ_INPUT := in_sdl.o
|
SYSOBJ_INPUT := in_sdl.o
|
||||||
|
@ -217,6 +223,7 @@ GLOBJS = \
|
||||||
gl_fog.o \
|
gl_fog.o \
|
||||||
gl_rmisc.o \
|
gl_rmisc.o \
|
||||||
r_part.o \
|
r_part.o \
|
||||||
|
r_part_fte.o \
|
||||||
r_world.o \
|
r_world.o \
|
||||||
gl_screen.o \
|
gl_screen.o \
|
||||||
gl_sky.o \
|
gl_sky.o \
|
||||||
|
@ -256,6 +263,7 @@ OBJS := strlcat.o \
|
||||||
wad.o \
|
wad.o \
|
||||||
cmd.o \
|
cmd.o \
|
||||||
common.o \
|
common.o \
|
||||||
|
fs_zip.o \
|
||||||
crc.o \
|
crc.o \
|
||||||
cvar.o \
|
cvar.o \
|
||||||
cfgfile.o \
|
cfgfile.o \
|
||||||
|
@ -263,6 +271,7 @@ OBJS := strlcat.o \
|
||||||
host_cmd.o \
|
host_cmd.o \
|
||||||
mathlib.o \
|
mathlib.o \
|
||||||
pr_cmds.o \
|
pr_cmds.o \
|
||||||
|
pr_ext.o \
|
||||||
pr_edict.o \
|
pr_edict.o \
|
||||||
pr_exec.o \
|
pr_exec.o \
|
||||||
sv_main.o \
|
sv_main.o \
|
||||||
|
|
|
@ -34,6 +34,7 @@ check_gcc = $(shell if echo | $(CC) $(1) -Werror -S -o /dev/null -xc - > /dev/nu
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
WINSOCK2?= 1
|
WINSOCK2?= 1
|
||||||
|
USE_ZLIB?= 1
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# build variables
|
# build variables
|
||||||
|
@ -101,11 +102,11 @@ $(error Invalid MP3LIB setting)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
ifeq ($(MP3LIB),mad)
|
ifeq ($(MP3LIB),mad)
|
||||||
mp3_obj=snd_mp3
|
mp3_obj=snd_mp3.o
|
||||||
lib_mp3dec=-lmad
|
lib_mp3dec=-lmad
|
||||||
endif
|
endif
|
||||||
ifeq ($(MP3LIB),mpg123)
|
ifeq ($(MP3LIB),mpg123)
|
||||||
mp3_obj=snd_mpg123
|
mp3_obj=snd_mpg123.o
|
||||||
lib_mp3dec=-lmpg123
|
lib_mp3dec=-lmpg123
|
||||||
endif
|
endif
|
||||||
ifeq ($(VORBISLIB),vorbis)
|
ifeq ($(VORBISLIB),vorbis)
|
||||||
|
@ -164,6 +165,11 @@ CFLAGS+= $(CODEC_INC)
|
||||||
|
|
||||||
COMMON_LIBS:= -lm -lopengl32 -lwinmm
|
COMMON_LIBS:= -lm -lopengl32 -lwinmm
|
||||||
|
|
||||||
|
ifeq ($(USE_ZLIB),1)
|
||||||
|
CFLAGS+= -DUSE_ZLIB
|
||||||
|
COMMON_LIBS+= `$(CC) -print-file-name=libz.a`
|
||||||
|
endif
|
||||||
|
|
||||||
LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
|
LIBS := $(COMMON_LIBS) $(NET_LIBS) $(CODEC_LINK) $(CODECLIBS)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
@ -193,12 +199,11 @@ MUSIC_OBJS:= bgmusic.o \
|
||||||
snd_wave.o \
|
snd_wave.o \
|
||||||
snd_vorbis.o \
|
snd_vorbis.o \
|
||||||
snd_opus.o \
|
snd_opus.o \
|
||||||
$(mp3_obj).o \
|
$(mp3_obj) \
|
||||||
snd_mp3tag.o \
|
|
||||||
snd_mikmod.o \
|
snd_mikmod.o \
|
||||||
snd_xmp.o \
|
snd_xmp.o \
|
||||||
snd_umx.o
|
snd_umx.o
|
||||||
COMOBJ_SND := snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
|
COMOBJ_SND := snd_voip.o snd_dma.o snd_mix.o snd_mem.o $(MUSIC_OBJS)
|
||||||
SYSOBJ_SND := snd_sdl.o
|
SYSOBJ_SND := snd_sdl.o
|
||||||
SYSOBJ_CDA := cd_sdl.o
|
SYSOBJ_CDA := cd_sdl.o
|
||||||
SYSOBJ_INPUT := in_sdl.o
|
SYSOBJ_INPUT := in_sdl.o
|
||||||
|
@ -215,6 +220,7 @@ GLOBJS = \
|
||||||
gl_fog.o \
|
gl_fog.o \
|
||||||
gl_rmisc.o \
|
gl_rmisc.o \
|
||||||
r_part.o \
|
r_part.o \
|
||||||
|
r_part_fte.o \
|
||||||
r_world.o \
|
r_world.o \
|
||||||
gl_screen.o \
|
gl_screen.o \
|
||||||
gl_sky.o \
|
gl_sky.o \
|
||||||
|
@ -254,6 +260,7 @@ OBJS := strlcat.o \
|
||||||
wad.o \
|
wad.o \
|
||||||
cmd.o \
|
cmd.o \
|
||||||
common.o \
|
common.o \
|
||||||
|
fs_zip.o \
|
||||||
crc.o \
|
crc.o \
|
||||||
cvar.o \
|
cvar.o \
|
||||||
cfgfile.o \
|
cfgfile.o \
|
||||||
|
@ -261,6 +268,7 @@ OBJS := strlcat.o \
|
||||||
host_cmd.o \
|
host_cmd.o \
|
||||||
mathlib.o \
|
mathlib.o \
|
||||||
pr_cmds.o \
|
pr_cmds.o \
|
||||||
|
pr_ext.o \
|
||||||
pr_edict.o \
|
pr_edict.o \
|
||||||
pr_exec.o \
|
pr_exec.o \
|
||||||
sv_main.o \
|
sv_main.o \
|
||||||
|
|
|
@ -21,6 +21,8 @@ MP3LIB=mad
|
||||||
VORBISLIB=vorbis
|
VORBISLIB=vorbis
|
||||||
|
|
||||||
WINSOCK2= 0
|
WINSOCK2= 0
|
||||||
|
#FIXME: set this to 1
|
||||||
|
USE_ZLIB=0
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# build variables
|
# build variables
|
||||||
|
@ -106,6 +108,10 @@ CFLAGS+= -DUSE_CODEC_UMX
|
||||||
CFLAGS+= $(CODEC_INC)
|
CFLAGS+= $(CODEC_INC)
|
||||||
|
|
||||||
COMMON_LIBS= opengl32.lib winmm.lib
|
COMMON_LIBS= opengl32.lib winmm.lib
|
||||||
|
!ifeq USE_ZLIB 1
|
||||||
|
CFLAGS+= -DUSE_ZLIB
|
||||||
|
COMMON_LIBS+= -lz
|
||||||
|
!endif
|
||||||
|
|
||||||
LIBS = $(CODECLIBS) $(SDL_LIBS) $(COMMON_LIBS) $(NET_LIBS)
|
LIBS = $(CODECLIBS) $(SDL_LIBS) $(COMMON_LIBS) $(NET_LIBS)
|
||||||
|
|
||||||
|
@ -145,7 +151,7 @@ MUSIC_OBJS= bgmusic.obj &
|
||||||
snd_mikmod.obj &
|
snd_mikmod.obj &
|
||||||
snd_xmp.obj &
|
snd_xmp.obj &
|
||||||
snd_umx.obj
|
snd_umx.obj
|
||||||
COMOBJ_SND = snd_dma.obj snd_mix.obj snd_mem.obj $(MUSIC_OBJS)
|
COMOBJ_SND = snd_voip.obj snd_dma.obj snd_mix.obj snd_mem.obj $(MUSIC_OBJS)
|
||||||
SYSOBJ_SND = snd_sdl.obj
|
SYSOBJ_SND = snd_sdl.obj
|
||||||
SYSOBJ_CDA = cd_sdl.obj
|
SYSOBJ_CDA = cd_sdl.obj
|
||||||
SYSOBJ_INPUT = in_sdl.obj
|
SYSOBJ_INPUT = in_sdl.obj
|
||||||
|
@ -167,6 +173,7 @@ GLOBJS = &
|
||||||
gl_fog.obj &
|
gl_fog.obj &
|
||||||
gl_rmisc.obj &
|
gl_rmisc.obj &
|
||||||
r_part.obj &
|
r_part.obj &
|
||||||
|
r_part_fte.obj &
|
||||||
r_world.obj &
|
r_world.obj &
|
||||||
gl_screen.obj &
|
gl_screen.obj &
|
||||||
gl_sky.obj &
|
gl_sky.obj &
|
||||||
|
@ -206,6 +213,7 @@ OBJS = strlcat.obj &
|
||||||
wad.obj &
|
wad.obj &
|
||||||
cmd.obj &
|
cmd.obj &
|
||||||
common.obj &
|
common.obj &
|
||||||
|
fs_zip.obj &
|
||||||
crc.obj &
|
crc.obj &
|
||||||
cvar.obj &
|
cvar.obj &
|
||||||
cfgfile.obj &
|
cfgfile.obj &
|
||||||
|
@ -213,6 +221,7 @@ OBJS = strlcat.obj &
|
||||||
host_cmd.obj &
|
host_cmd.obj &
|
||||||
mathlib.obj &
|
mathlib.obj &
|
||||||
pr_cmds.obj &
|
pr_cmds.obj &
|
||||||
|
pr_ext.obj &
|
||||||
pr_edict.obj &
|
pr_edict.obj &
|
||||||
pr_exec.obj &
|
pr_exec.obj &
|
||||||
sv_main.obj &
|
sv_main.obj &
|
||||||
|
|
|
@ -98,7 +98,23 @@ typedef struct
|
||||||
int headnode[MAX_MAP_HULLS];
|
int headnode[MAX_MAP_HULLS];
|
||||||
int visleafs; // not including the solid leaf 0
|
int visleafs; // not including the solid leaf 0
|
||||||
int firstface, numfaces;
|
int firstface, numfaces;
|
||||||
} dmodel_t;
|
} mmodel_t;
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float mins[3], maxs[3];
|
||||||
|
float origin[3];
|
||||||
|
int headnode[4];
|
||||||
|
int visleafs; // not including the solid leaf 0
|
||||||
|
int firstface, numfaces;
|
||||||
|
} dmodelq1_t;
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float mins[3], maxs[3];
|
||||||
|
float origin[3];
|
||||||
|
int headnode[8];
|
||||||
|
int visleafs; // not including the solid leaf 0
|
||||||
|
int firstface, numfaces;
|
||||||
|
} dmodelh2_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -111,7 +111,7 @@ void Chase_UpdateForDrawing (void)
|
||||||
|
|
||||||
// calculate camera angles to look at the same spot
|
// calculate camera angles to look at the same spot
|
||||||
VectorSubtract (crosshair, r_refdef.vieworg, temp);
|
VectorSubtract (crosshair, r_refdef.vieworg, temp);
|
||||||
VectorAngles (temp, r_refdef.viewangles);
|
VectorAngles (temp, NULL, r_refdef.viewangles);
|
||||||
if (r_refdef.viewangles[PITCH] == 90 || r_refdef.viewangles[PITCH] == -90)
|
if (r_refdef.viewangles[PITCH] == 90 || r_refdef.viewangles[PITCH] == -90)
|
||||||
r_refdef.viewangles[YAW] = cl.viewangles[YAW];
|
r_refdef.viewangles[YAW] = cl.viewangles[YAW];
|
||||||
}
|
}
|
||||||
|
|
318
Quake/cl_demo.c
318
Quake/cl_demo.c
|
@ -36,10 +36,6 @@ read from the demo file.
|
||||||
==============================================================================
|
==============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// from ProQuake: space to fill out the demo header for record at any time
|
|
||||||
static byte demo_head[3][MAX_MSGLEN];
|
|
||||||
static int demo_head_size[2];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============
|
==============
|
||||||
CL_StopPlayback
|
CL_StopPlayback
|
||||||
|
@ -166,14 +162,6 @@ int CL_GetMessage (void)
|
||||||
if (cls.demorecording)
|
if (cls.demorecording)
|
||||||
CL_WriteDemoMessage ();
|
CL_WriteDemoMessage ();
|
||||||
|
|
||||||
if (cls.signon < 2)
|
|
||||||
{
|
|
||||||
// record messages before full connection, so that a
|
|
||||||
// demo record can happen after connection is done
|
|
||||||
memcpy(demo_head[cls.signon], net_message.data, net_message.cursize);
|
|
||||||
demo_head_size[cls.signon] = net_message.cursize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,10 +195,234 @@ void CL_Stop_f (void)
|
||||||
cls.demorecording = false;
|
cls.demorecording = false;
|
||||||
Con_Printf ("Completed demo\n");
|
Con_Printf ("Completed demo\n");
|
||||||
|
|
||||||
|
Cvar_SetROM(cl_recordingdemo.name, "");
|
||||||
|
|
||||||
// ericw -- update demo tab-completion list
|
// ericw -- update demo tab-completion list
|
||||||
DemoList_Rebuild ();
|
DemoList_Rebuild ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CL_Record_Serverdata(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
MSG_WriteByte(&net_message, svc_serverinfo);
|
||||||
|
if (cl.protocol_pext2)
|
||||||
|
{
|
||||||
|
MSG_WriteLong (&net_message, PROTOCOL_FTE_PEXT2);
|
||||||
|
MSG_WriteLong (&net_message, cl.protocol_pext2);
|
||||||
|
}
|
||||||
|
MSG_WriteLong (&net_message, cl.protocol);
|
||||||
|
if (cl.protocol == PROTOCOL_RMQ)
|
||||||
|
MSG_WriteLong (&net_message, cl.protocolflags);
|
||||||
|
if (cl.protocol_pext2 & PEXT2_PREDINFO)
|
||||||
|
MSG_WriteString(&net_message, COM_SkipPath(com_gamedir));
|
||||||
|
MSG_WriteByte (&net_message, cl.maxclients);
|
||||||
|
MSG_WriteByte (&net_message, cl.gametype);
|
||||||
|
MSG_WriteString (&net_message, cl.levelname);
|
||||||
|
for (i=1; cl.model_precache[i]; i++)
|
||||||
|
MSG_WriteString (&net_message, cl.model_precache[i]->name);
|
||||||
|
MSG_WriteByte (&net_message, 0);
|
||||||
|
for (i=1; cl.sound_precache[i]; i++) //FIXME: might not send any if nosound is set
|
||||||
|
MSG_WriteString (&net_message, cl.sound_precache[i]->name);
|
||||||
|
MSG_WriteByte (&net_message, 0);
|
||||||
|
//FIXME: cd track (current rather than initial?)
|
||||||
|
//FIXME: initial view entity (for clients that don't want to mess up scoreboards)
|
||||||
|
MSG_WriteByte (&net_message, svc_signonnum);
|
||||||
|
MSG_WriteByte (&net_message, 1);
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
//spins out a baseline(idx>=0) or static entity(idx<0) into net_message
|
||||||
|
void CL_Record_Prespawn(void)
|
||||||
|
{
|
||||||
|
int idx, i;
|
||||||
|
|
||||||
|
//baselines
|
||||||
|
for (idx = 0; idx < cl.num_entities; idx++)
|
||||||
|
{
|
||||||
|
entity_state_t *state = &cl.entities[idx].baseline;
|
||||||
|
if (!memcmp(state, &nullentitystate, sizeof(entity_state_t)))
|
||||||
|
continue; //no need
|
||||||
|
MSG_WriteStaticOrBaseLine(&net_message, idx, state, cl.protocol_pext2, cl.protocol, cl.protocolflags);
|
||||||
|
|
||||||
|
if (net_message.cursize > 4096)
|
||||||
|
{ //periodically flush so that large maps don't need larger than vanilla limits
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static ents
|
||||||
|
for (idx = 1; idx < cl.num_statics; idx++)
|
||||||
|
{
|
||||||
|
MSG_WriteStaticOrBaseLine(&net_message, -1, &cl.static_entities[idx]->baseline, cl.protocol_pext2, cl.protocol, cl.protocolflags);
|
||||||
|
|
||||||
|
if (net_message.cursize > 4096)
|
||||||
|
{ //periodically flush so that large maps don't need larger than vanilla limits
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static sounds
|
||||||
|
for (i = NUM_AMBIENTS; i < total_channels; i++)
|
||||||
|
{
|
||||||
|
channel_t *ss = &snd_channels[i];
|
||||||
|
sfxcache_t *sc;
|
||||||
|
|
||||||
|
if (!ss->sfx)
|
||||||
|
continue;
|
||||||
|
if (ss->entnum || ss->entchannel)
|
||||||
|
continue; //can't have been a static sound
|
||||||
|
sc = S_LoadSound(ss->sfx);
|
||||||
|
if (!sc || sc->loopstart == -1)
|
||||||
|
continue; //can't have been a (valid) static sound
|
||||||
|
|
||||||
|
for (idx = 1; idx < MAX_SOUNDS && cl.sound_precache[idx]; idx++)
|
||||||
|
if (cl.sound_precache[idx] == ss->sfx)
|
||||||
|
break;
|
||||||
|
if (idx == MAX_SOUNDS)
|
||||||
|
continue; //can't figure out which sound it was
|
||||||
|
|
||||||
|
MSG_WriteByte(&net_message, (idx > 255)?svc_spawnstaticsound2:svc_spawnstaticsound);
|
||||||
|
MSG_WriteCoord(&net_message, ss->origin[0], cl.protocolflags);
|
||||||
|
MSG_WriteCoord(&net_message, ss->origin[1], cl.protocolflags);
|
||||||
|
MSG_WriteCoord(&net_message, ss->origin[2], cl.protocolflags);
|
||||||
|
if (idx > 255)
|
||||||
|
MSG_WriteShort(&net_message, idx);
|
||||||
|
else
|
||||||
|
MSG_WriteByte(&net_message, idx);
|
||||||
|
MSG_WriteByte(&net_message, ss->master_vol);
|
||||||
|
MSG_WriteByte(&net_message, ss->dist_mult*1000*64);
|
||||||
|
|
||||||
|
if (net_message.cursize > 4096)
|
||||||
|
{ //periodically flush so that large maps don't need larger than vanilla limits
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
//particleindexes
|
||||||
|
for (idx = 0; idx < MAX_PARTICLETYPES; idx++)
|
||||||
|
{
|
||||||
|
if (!cl.particle_precache[idx].name)
|
||||||
|
continue;
|
||||||
|
MSG_WriteByte(&net_message, svcdp_precache);
|
||||||
|
MSG_WriteShort(&net_message, 0x4000 | idx);
|
||||||
|
MSG_WriteString(&net_message, cl.particle_precache[idx].name);
|
||||||
|
|
||||||
|
if (net_message.cursize > 4096)
|
||||||
|
{ //periodically flush so that large maps don't need larger than vanilla limits
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MSG_WriteByte (&net_message, svc_signonnum);
|
||||||
|
MSG_WriteByte (&net_message, 2);
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CL_Record_Spawn(void)
|
||||||
|
{
|
||||||
|
const char *cmd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// player names, colors, and frag counts
|
||||||
|
for (i = 0; i < cl.maxclients; i++)
|
||||||
|
{
|
||||||
|
MSG_WriteByte (&net_message, svc_updatename);
|
||||||
|
MSG_WriteByte (&net_message, i);
|
||||||
|
MSG_WriteString (&net_message, cl.scores[i].name);
|
||||||
|
MSG_WriteByte (&net_message, svc_updatefrags);
|
||||||
|
MSG_WriteByte (&net_message, i);
|
||||||
|
MSG_WriteShort (&net_message, cl.scores[i].frags);
|
||||||
|
MSG_WriteByte (&net_message, svc_updatecolors);
|
||||||
|
MSG_WriteByte (&net_message, i);
|
||||||
|
MSG_WriteByte (&net_message, cl.scores[i].colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send all current light styles
|
||||||
|
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
||||||
|
{
|
||||||
|
if (*cl_lightstyle[i].map)
|
||||||
|
{
|
||||||
|
MSG_WriteByte (&net_message, svc_lightstyle);
|
||||||
|
MSG_WriteByte (&net_message, i);
|
||||||
|
MSG_WriteString (&net_message, cl_lightstyle[i].map);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (net_message.cursize > 4096)
|
||||||
|
{ //periodically flush so that large maps don't need larger than vanilla limits
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// what about the current CD track... future consideration.
|
||||||
|
|
||||||
|
//if this mod is using dynamic fog, make sure we start with the right values.
|
||||||
|
cmd = Fog_GetFogCommand();
|
||||||
|
if (cmd)
|
||||||
|
{
|
||||||
|
MSG_WriteByte (&net_message, svc_stufftext);
|
||||||
|
MSG_WriteString (&net_message, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
//stats
|
||||||
|
for (i = 0; i < MAX_CL_STATS; i++)
|
||||||
|
{
|
||||||
|
if (!cl.stats[i] && !cl.statsf[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (net_message.cursize > 4096)
|
||||||
|
{ //periodically flush so that large maps don't need larger than vanilla limits
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((double)cl.stats[i] != cl.statsf[i] && (unsigned int)cl.stats[i] <= 0x00ffffff)
|
||||||
|
{ //if the float representation seems to have more precision then use that, unless its getting huge in which case we're probably getting fpu truncation, so go back to more compatible ints
|
||||||
|
MSG_WriteByte (&net_message, svcfte_updatestatfloat);
|
||||||
|
MSG_WriteByte (&net_message, i);
|
||||||
|
MSG_WriteFloat (&net_message, cl.statsf[i]);
|
||||||
|
}
|
||||||
|
else if (cl.stats[i] >= 0 && cl.stats[i] <= 255 && (cl.protocol_pext2 & PEXT2_PREDINFO))
|
||||||
|
{
|
||||||
|
MSG_WriteByte (&net_message, svcdp_updatestatbyte);
|
||||||
|
MSG_WriteByte (&net_message, i);
|
||||||
|
MSG_WriteByte (&net_message, cl.stats[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MSG_WriteByte (&net_message, svc_updatestat);
|
||||||
|
MSG_WriteByte (&net_message, i);
|
||||||
|
MSG_WriteLong (&net_message, cl.stats[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// view entity
|
||||||
|
MSG_WriteByte (&net_message, svc_setview);
|
||||||
|
MSG_WriteShort (&net_message, cl.viewentity);
|
||||||
|
|
||||||
|
// signon
|
||||||
|
MSG_WriteByte (&net_message, svc_signonnum);
|
||||||
|
MSG_WriteByte (&net_message, 3);
|
||||||
|
|
||||||
|
CL_WriteDemoMessage();
|
||||||
|
SZ_Clear (&net_message);
|
||||||
|
|
||||||
|
//ask the server to reset entity deltas. yes this means playback will wait a couple of frames before it actually starts playing but oh well.
|
||||||
|
if (cl.protocol_pext2 & PEXT2_REPLACEMENTDELTAS)
|
||||||
|
{
|
||||||
|
cl.ackframes_count = 0;
|
||||||
|
cl.ackframes[cl.ackframes_count++] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
====================
|
====================
|
||||||
CL_Record_f
|
CL_Record_f
|
||||||
|
@ -260,6 +472,23 @@ void CL_Record_f (void)
|
||||||
Con_Printf("Can't record - try again when connected\n");
|
Con_Printf("Can't record - try again when connected\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
switch(cl.protocol)
|
||||||
|
{
|
||||||
|
case PROTOCOL_NETQUAKE:
|
||||||
|
case PROTOCOL_FITZQUAKE:
|
||||||
|
case PROTOCOL_RMQ:
|
||||||
|
case PROTOCOL_VERSION_BJP3:
|
||||||
|
break;
|
||||||
|
//case PROTOCOL_VERSION_NEHD:
|
||||||
|
//case PROTOCOL_VERSION_DP5:
|
||||||
|
//case PROTOCOL_VERSION_DP6:
|
||||||
|
case PROTOCOL_VERSION_DP7:
|
||||||
|
//case PROTOCOL_VERSION_BJP1:
|
||||||
|
//case PROTOCOL_VERSION_BJP2:
|
||||||
|
default:
|
||||||
|
Con_Printf("Can not record - protocol not supported for recording mid-map\nClient demo recording must be started before connecting\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the forced cd track number, or -1
|
// write the forced cd track number, or -1
|
||||||
|
@ -286,11 +515,14 @@ void CL_Record_f (void)
|
||||||
// open the demo file
|
// open the demo file
|
||||||
COM_AddExtension (name, ".dem", sizeof(name));
|
COM_AddExtension (name, ".dem", sizeof(name));
|
||||||
|
|
||||||
|
Cvar_SetROM(cl_recordingdemo.name, name);
|
||||||
|
|
||||||
Con_Printf ("recording to %s.\n", name);
|
Con_Printf ("recording to %s.\n", name);
|
||||||
cls.demofile = fopen (name, "wb");
|
cls.demofile = fopen (name, "wb");
|
||||||
if (!cls.demofile)
|
if (!cls.demofile)
|
||||||
{
|
{
|
||||||
Con_Printf ("ERROR: couldn't create %s\n", name);
|
Con_Printf ("ERROR: couldn't create %s\n", name);
|
||||||
|
Cvar_SetROM(cl_recordingdemo.name, "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,66 +536,14 @@ void CL_Record_f (void)
|
||||||
{
|
{
|
||||||
byte *data = net_message.data;
|
byte *data = net_message.data;
|
||||||
int cursize = net_message.cursize;
|
int cursize = net_message.cursize;
|
||||||
int i;
|
byte weirdaltbufferthatprobablyisntneeded[NET_MAXMESSAGE];
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
net_message.data = weirdaltbufferthatprobablyisntneeded;
|
||||||
{
|
|
||||||
net_message.data = demo_head[i];
|
|
||||||
net_message.cursize = demo_head_size[i];
|
|
||||||
CL_WriteDemoMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
net_message.data = demo_head[2];
|
|
||||||
SZ_Clear (&net_message);
|
SZ_Clear (&net_message);
|
||||||
|
|
||||||
// current names, colors, and frag counts
|
CL_Record_Serverdata();
|
||||||
for (i = 0; i < cl.maxclients; i++)
|
CL_Record_Prespawn();
|
||||||
{
|
CL_Record_Spawn();
|
||||||
MSG_WriteByte (&net_message, svc_updatename);
|
|
||||||
MSG_WriteByte (&net_message, i);
|
|
||||||
MSG_WriteString (&net_message, cl.scores[i].name);
|
|
||||||
MSG_WriteByte (&net_message, svc_updatefrags);
|
|
||||||
MSG_WriteByte (&net_message, i);
|
|
||||||
MSG_WriteShort (&net_message, cl.scores[i].frags);
|
|
||||||
MSG_WriteByte (&net_message, svc_updatecolors);
|
|
||||||
MSG_WriteByte (&net_message, i);
|
|
||||||
MSG_WriteByte (&net_message, cl.scores[i].colors);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send all current light styles
|
|
||||||
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
|
||||||
{
|
|
||||||
MSG_WriteByte (&net_message, svc_lightstyle);
|
|
||||||
MSG_WriteByte (&net_message, i);
|
|
||||||
MSG_WriteString (&net_message, cl_lightstyle[i].map);
|
|
||||||
}
|
|
||||||
|
|
||||||
// what about the CD track or SVC fog... future consideration.
|
|
||||||
MSG_WriteByte (&net_message, svc_updatestat);
|
|
||||||
MSG_WriteByte (&net_message, STAT_TOTALSECRETS);
|
|
||||||
MSG_WriteLong (&net_message, cl.stats[STAT_TOTALSECRETS]);
|
|
||||||
|
|
||||||
MSG_WriteByte (&net_message, svc_updatestat);
|
|
||||||
MSG_WriteByte (&net_message, STAT_TOTALMONSTERS);
|
|
||||||
MSG_WriteLong (&net_message, cl.stats[STAT_TOTALMONSTERS]);
|
|
||||||
|
|
||||||
MSG_WriteByte (&net_message, svc_updatestat);
|
|
||||||
MSG_WriteByte (&net_message, STAT_SECRETS);
|
|
||||||
MSG_WriteLong (&net_message, cl.stats[STAT_SECRETS]);
|
|
||||||
|
|
||||||
MSG_WriteByte (&net_message, svc_updatestat);
|
|
||||||
MSG_WriteByte (&net_message, STAT_MONSTERS);
|
|
||||||
MSG_WriteLong (&net_message, cl.stats[STAT_MONSTERS]);
|
|
||||||
|
|
||||||
// view entity
|
|
||||||
MSG_WriteByte (&net_message, svc_setview);
|
|
||||||
MSG_WriteShort (&net_message, cl.viewentity);
|
|
||||||
|
|
||||||
// signon
|
|
||||||
MSG_WriteByte (&net_message, svc_signonnum);
|
|
||||||
MSG_WriteByte (&net_message, 3);
|
|
||||||
|
|
||||||
CL_WriteDemoMessage();
|
|
||||||
|
|
||||||
// restore net_message
|
// restore net_message
|
||||||
net_message.data = data;
|
net_message.data = data;
|
||||||
|
|
196
Quake/cl_input.c
196
Quake/cl_input.c
|
@ -54,7 +54,7 @@ state bit 2 is edge triggered on the down to up transition
|
||||||
kbutton_t in_mlook, in_klook;
|
kbutton_t in_mlook, in_klook;
|
||||||
kbutton_t in_left, in_right, in_forward, in_back;
|
kbutton_t in_left, in_right, in_forward, in_back;
|
||||||
kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
|
kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
|
||||||
kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack;
|
kbutton_t in_strafe, in_speed, in_jump, in_attack, in_button3, in_button4, in_button5, in_button6, in_button7, in_button8;
|
||||||
kbutton_t in_up, in_down;
|
kbutton_t in_up, in_down;
|
||||||
|
|
||||||
int in_impulse;
|
int in_impulse;
|
||||||
|
@ -156,11 +156,24 @@ void IN_StrafeUp(void) {KeyUp(&in_strafe);}
|
||||||
void IN_AttackDown(void) {KeyDown(&in_attack);}
|
void IN_AttackDown(void) {KeyDown(&in_attack);}
|
||||||
void IN_AttackUp(void) {KeyUp(&in_attack);}
|
void IN_AttackUp(void) {KeyUp(&in_attack);}
|
||||||
|
|
||||||
void IN_UseDown (void) {KeyDown(&in_use);}
|
void IN_UseDown (void) {KeyDown(&in_button3);}
|
||||||
void IN_UseUp (void) {KeyUp(&in_use);}
|
void IN_UseUp (void) {KeyUp(&in_button3);}
|
||||||
void IN_JumpDown (void) {KeyDown(&in_jump);}
|
void IN_JumpDown (void) {KeyDown(&in_jump);}
|
||||||
void IN_JumpUp (void) {KeyUp(&in_jump);}
|
void IN_JumpUp (void) {KeyUp(&in_jump);}
|
||||||
|
|
||||||
|
void IN_Button3Down(void) {KeyDown(&in_button3);}
|
||||||
|
void IN_Button3Up(void) {KeyUp(&in_button3);}
|
||||||
|
void IN_Button4Down(void) {KeyDown(&in_button4);}
|
||||||
|
void IN_Button4Up(void) {KeyUp(&in_button4);}
|
||||||
|
void IN_Button5Down(void) {KeyDown(&in_button5);}
|
||||||
|
void IN_Button5Up(void) {KeyUp(&in_button5);}
|
||||||
|
void IN_Button6Down(void) {KeyDown(&in_button6);}
|
||||||
|
void IN_Button6Up(void) {KeyUp(&in_button6);}
|
||||||
|
void IN_Button7Down(void) {KeyDown(&in_button7);}
|
||||||
|
void IN_Button7Up(void) {KeyUp(&in_button7);}
|
||||||
|
void IN_Button8Down(void) {KeyDown(&in_button8);}
|
||||||
|
void IN_Button8Up(void) {KeyUp(&in_button8);}
|
||||||
|
|
||||||
void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));}
|
void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -339,65 +352,134 @@ CL_SendMove
|
||||||
*/
|
*/
|
||||||
void CL_SendMove (const usercmd_t *cmd)
|
void CL_SendMove (const usercmd_t *cmd)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
int bits;
|
int bits;
|
||||||
sizebuf_t buf;
|
sizebuf_t buf;
|
||||||
byte data[128];
|
byte data[1024];
|
||||||
|
|
||||||
buf.maxsize = 128;
|
buf.maxsize = sizeof(data);
|
||||||
buf.cursize = 0;
|
buf.cursize = 0;
|
||||||
buf.data = data;
|
buf.data = data;
|
||||||
|
|
||||||
cl.cmd = *cmd;
|
for (i = 0; i < cl.ackframes_count; i++)
|
||||||
|
{
|
||||||
|
MSG_WriteByte(&buf, clcdp_ackframe);
|
||||||
|
MSG_WriteLong(&buf, cl.ackframes[i]);
|
||||||
|
}
|
||||||
|
cl.ackframes_count = 0;
|
||||||
|
|
||||||
//
|
if (cmd)
|
||||||
// send the movement message
|
{
|
||||||
//
|
int dump = buf.cursize;
|
||||||
MSG_WriteByte (&buf, clc_move);
|
cl.cmd = *cmd;
|
||||||
|
|
||||||
MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
|
//
|
||||||
|
// send the movement message
|
||||||
|
//
|
||||||
|
MSG_WriteByte (&buf, clc_move);
|
||||||
|
|
||||||
for (i=0 ; i<3 ; i++)
|
if (cl.protocol == PROTOCOL_VERSION_DP7)
|
||||||
//johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE
|
{
|
||||||
if (cl.protocol == PROTOCOL_NETQUAKE)
|
if (1)
|
||||||
MSG_WriteAngle (&buf, cl.viewangles[i], cl.protocolflags);
|
MSG_WriteLong(&buf, 0);
|
||||||
|
else
|
||||||
|
MSG_WriteLong(&buf, cl.movemessages);
|
||||||
|
}
|
||||||
|
else if (cl.protocol_pext2 & PEXT2_PREDINFO)
|
||||||
|
MSG_WriteShort(&buf, cl.movemessages&0xffff); //server will ack this once it has been applied to the player's entity state
|
||||||
|
MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
|
||||||
|
|
||||||
|
for (i=0 ; i<3 ; i++)
|
||||||
|
//johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE
|
||||||
|
//spike -- nq+bjp3 use 8bit angles. all other supported protocols use 16bit ones.
|
||||||
|
//spike -- proquake servers bump client->server angles up to at least 16bit. this is safe because it only happens when both client+server advertise it, and because it never actually gets recorded into demos anyway.
|
||||||
|
//spike -- predinfo also always means 16bit angles, even if for some reason the server doesn't advertise proquake (like dp).
|
||||||
|
if ((cl.protocol == PROTOCOL_NETQUAKE || cl.protocol == PROTOCOL_VERSION_BJP3) && !NET_QSocketGetProQuakeAngleHack(cls.netcon) && !(cl.protocol_pext2 & PEXT2_PREDINFO))
|
||||||
|
MSG_WriteAngle (&buf, cl.viewangles[i], cl.protocolflags);
|
||||||
|
else
|
||||||
|
MSG_WriteAngle16 (&buf, cl.viewangles[i], cl.protocolflags);
|
||||||
|
//johnfitz
|
||||||
|
|
||||||
|
MSG_WriteShort (&buf, cmd->forwardmove);
|
||||||
|
MSG_WriteShort (&buf, cmd->sidemove);
|
||||||
|
MSG_WriteShort (&buf, cmd->upmove);
|
||||||
|
|
||||||
|
//
|
||||||
|
// send button bits
|
||||||
|
//
|
||||||
|
bits = 0;
|
||||||
|
|
||||||
|
if ( in_attack.state & 3 )
|
||||||
|
bits |= 1;
|
||||||
|
in_attack.state &= ~2;
|
||||||
|
|
||||||
|
if (in_jump.state & 3)
|
||||||
|
bits |= 2;
|
||||||
|
in_jump.state &= ~2;
|
||||||
|
|
||||||
|
if (in_button3.state & 3)
|
||||||
|
bits |= 4;
|
||||||
|
in_button3.state &= ~2;
|
||||||
|
|
||||||
|
if (in_button4.state & 3)
|
||||||
|
bits |= 8;
|
||||||
|
in_button4.state &= ~2;
|
||||||
|
|
||||||
|
if (in_button5.state & 3)
|
||||||
|
bits |= 16;
|
||||||
|
in_button5.state &= ~2;
|
||||||
|
|
||||||
|
if (in_button6.state & 3)
|
||||||
|
bits |= 32;
|
||||||
|
in_button6.state &= ~2;
|
||||||
|
|
||||||
|
if (in_button7.state & 3)
|
||||||
|
bits |= 64;
|
||||||
|
in_button7.state &= ~2;
|
||||||
|
|
||||||
|
if (in_button8.state & 3)
|
||||||
|
bits |= 128;
|
||||||
|
in_button8.state &= ~2;
|
||||||
|
|
||||||
|
if (cl.protocol == PROTOCOL_VERSION_DP7)
|
||||||
|
{
|
||||||
|
MSG_WriteLong (&buf, bits);
|
||||||
|
MSG_WriteByte (&buf, in_impulse);
|
||||||
|
MSG_WriteShort(&buf, 32767);//cursor x
|
||||||
|
MSG_WriteShort(&buf, 32767);//cursor y
|
||||||
|
MSG_WriteFloat(&buf, r_refdef.vieworg[0]); //start (view pos)
|
||||||
|
MSG_WriteFloat(&buf, r_refdef.vieworg[1]);
|
||||||
|
MSG_WriteFloat(&buf, r_refdef.vieworg[2]);
|
||||||
|
MSG_WriteFloat(&buf, r_refdef.vieworg[0]); //impact
|
||||||
|
MSG_WriteFloat(&buf, r_refdef.vieworg[1]);
|
||||||
|
MSG_WriteFloat(&buf, r_refdef.vieworg[2]);
|
||||||
|
MSG_WriteShort(&buf, 0); //entity
|
||||||
|
}
|
||||||
else
|
else
|
||||||
MSG_WriteAngle16 (&buf, cl.viewangles[i], cl.protocolflags);
|
{
|
||||||
//johnfitz
|
MSG_WriteByte (&buf, bits);
|
||||||
|
MSG_WriteByte (&buf, in_impulse);
|
||||||
|
}
|
||||||
|
in_impulse = 0;
|
||||||
|
|
||||||
MSG_WriteShort (&buf, cmd->forwardmove);
|
//
|
||||||
MSG_WriteShort (&buf, cmd->sidemove);
|
// allways dump the first two message, because it may contain leftover inputs
|
||||||
MSG_WriteShort (&buf, cmd->upmove);
|
// from the last level
|
||||||
|
//
|
||||||
|
if (++cl.movemessages <= 2)
|
||||||
|
buf.cursize = dump;
|
||||||
|
else
|
||||||
|
S_Voip_Transmit(clcfte_voicechat, &buf);/*Spike: Add voice data*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
S_Voip_Transmit(clcfte_voicechat, NULL);/*Spike: Add voice data (with cl_voip_test anyway)*/
|
||||||
|
|
||||||
//
|
//fixme: nops if we're still connecting, or something.
|
||||||
// send button bits
|
|
||||||
//
|
|
||||||
bits = 0;
|
|
||||||
|
|
||||||
if ( in_attack.state & 3 )
|
//
|
||||||
bits |= 1;
|
// deliver the message
|
||||||
in_attack.state &= ~2;
|
//
|
||||||
|
if (cls.demoplayback || !buf.cursize)
|
||||||
if (in_jump.state & 3)
|
|
||||||
bits |= 2;
|
|
||||||
in_jump.state &= ~2;
|
|
||||||
|
|
||||||
MSG_WriteByte (&buf, bits);
|
|
||||||
|
|
||||||
MSG_WriteByte (&buf, in_impulse);
|
|
||||||
in_impulse = 0;
|
|
||||||
|
|
||||||
//
|
|
||||||
// deliver the message
|
|
||||||
//
|
|
||||||
if (cls.demoplayback)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//
|
|
||||||
// allways dump the first two message, because it may contain leftover inputs
|
|
||||||
// from the last level
|
|
||||||
//
|
|
||||||
if (++cl.movemessages <= 2)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
|
if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
|
||||||
|
@ -442,6 +524,18 @@ void CL_InitInput (void)
|
||||||
Cmd_AddCommand ("-attack", IN_AttackUp);
|
Cmd_AddCommand ("-attack", IN_AttackUp);
|
||||||
Cmd_AddCommand ("+use", IN_UseDown);
|
Cmd_AddCommand ("+use", IN_UseDown);
|
||||||
Cmd_AddCommand ("-use", IN_UseUp);
|
Cmd_AddCommand ("-use", IN_UseUp);
|
||||||
|
Cmd_AddCommand ("+button3", IN_Button3Down);
|
||||||
|
Cmd_AddCommand ("-button3", IN_Button3Up);
|
||||||
|
Cmd_AddCommand ("+button4", IN_Button4Down);
|
||||||
|
Cmd_AddCommand ("-button4", IN_Button4Up);
|
||||||
|
Cmd_AddCommand ("+button5", IN_Button5Down);
|
||||||
|
Cmd_AddCommand ("-button5", IN_Button5Up);
|
||||||
|
Cmd_AddCommand ("+button6", IN_Button6Down);
|
||||||
|
Cmd_AddCommand ("-button6", IN_Button6Up);
|
||||||
|
Cmd_AddCommand ("+button7", IN_Button7Down);
|
||||||
|
Cmd_AddCommand ("-button7", IN_Button7Up);
|
||||||
|
Cmd_AddCommand ("+button8", IN_Button8Down);
|
||||||
|
Cmd_AddCommand ("-button8", IN_Button8Up);
|
||||||
Cmd_AddCommand ("+jump", IN_JumpDown);
|
Cmd_AddCommand ("+jump", IN_JumpDown);
|
||||||
Cmd_AddCommand ("-jump", IN_JumpUp);
|
Cmd_AddCommand ("-jump", IN_JumpUp);
|
||||||
Cmd_AddCommand ("impulse", IN_Impulse);
|
Cmd_AddCommand ("impulse", IN_Impulse);
|
||||||
|
|
639
Quake/cl_main.c
639
Quake/cl_main.c
|
@ -24,6 +24,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
#include "bgmusic.h"
|
#include "bgmusic.h"
|
||||||
|
|
||||||
|
#include "arch_def.h"
|
||||||
|
#ifdef PLATFORM_UNIX
|
||||||
|
//for unlink
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// we need to declare some mouse variables here, because the menu system
|
// we need to declare some mouse variables here, because the menu system
|
||||||
// references them even when on a unix system.
|
// references them even when on a unix system.
|
||||||
|
|
||||||
|
@ -48,21 +54,39 @@ cvar_t m_side = {"m_side","0.8", CVAR_ARCHIVE};
|
||||||
cvar_t cl_maxpitch = {"cl_maxpitch", "90", CVAR_ARCHIVE}; //johnfitz -- variable pitch clamping
|
cvar_t cl_maxpitch = {"cl_maxpitch", "90", CVAR_ARCHIVE}; //johnfitz -- variable pitch clamping
|
||||||
cvar_t cl_minpitch = {"cl_minpitch", "-90", CVAR_ARCHIVE}; //johnfitz -- variable pitch clamping
|
cvar_t cl_minpitch = {"cl_minpitch", "-90", CVAR_ARCHIVE}; //johnfitz -- variable pitch clamping
|
||||||
|
|
||||||
|
cvar_t cl_recordingdemo = {"cl_recordingdemo", "", CVAR_ROM}; //the name of the currently-recording demo.
|
||||||
|
|
||||||
client_static_t cls;
|
client_static_t cls;
|
||||||
client_state_t cl;
|
client_state_t cl;
|
||||||
// FIXME: put these on hunk?
|
// FIXME: put these on hunk?
|
||||||
entity_t cl_static_entities[MAX_STATIC_ENTITIES];
|
|
||||||
lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
|
lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
|
||||||
dlight_t cl_dlights[MAX_DLIGHTS];
|
dlight_t cl_dlights[MAX_DLIGHTS];
|
||||||
|
|
||||||
entity_t *cl_entities; //johnfitz -- was a static array, now on hunk
|
|
||||||
int cl_max_edicts; //johnfitz -- only changes when new map loads
|
|
||||||
|
|
||||||
int cl_numvisedicts;
|
int cl_numvisedicts;
|
||||||
entity_t *cl_visedicts[MAX_VISEDICTS];
|
int cl_maxvisedicts;
|
||||||
|
entity_t **cl_visedicts;
|
||||||
|
|
||||||
extern cvar_t r_lerpmodels, r_lerpmove; //johnfitz
|
extern cvar_t r_lerpmodels, r_lerpmove; //johnfitz
|
||||||
|
|
||||||
|
void CL_ClearTrailStates(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < cl.num_statics; i++)
|
||||||
|
{
|
||||||
|
PScript_DelinkTrailstate(&(cl.static_entities[i]->trailstate));
|
||||||
|
PScript_DelinkTrailstate(&(cl.static_entities[i]->emitstate));
|
||||||
|
}
|
||||||
|
for (i = 0; i < cl.max_edicts; i++)
|
||||||
|
{
|
||||||
|
PScript_DelinkTrailstate(&(cl.entities[i].trailstate));
|
||||||
|
PScript_DelinkTrailstate(&(cl.entities[i].emitstate));
|
||||||
|
}
|
||||||
|
for (i = 0; i < MAX_BEAMS; i++)
|
||||||
|
{
|
||||||
|
PScript_DelinkTrailstate(&(cl_beams[i].trailstate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=====================
|
=====================
|
||||||
CL_ClearState
|
CL_ClearState
|
||||||
|
@ -74,6 +98,8 @@ void CL_ClearState (void)
|
||||||
if (!sv.active)
|
if (!sv.active)
|
||||||
Host_ClearMemory ();
|
Host_ClearMemory ();
|
||||||
|
|
||||||
|
CL_ClearTrailStates();
|
||||||
|
|
||||||
// wipe the entire cl structure
|
// wipe the entire cl structure
|
||||||
memset (&cl, 0, sizeof(cl));
|
memset (&cl, 0, sizeof(cl));
|
||||||
|
|
||||||
|
@ -86,9 +112,14 @@ void CL_ClearState (void)
|
||||||
memset (cl_beams, 0, sizeof(cl_beams));
|
memset (cl_beams, 0, sizeof(cl_beams));
|
||||||
|
|
||||||
//johnfitz -- cl_entities is now dynamically allocated
|
//johnfitz -- cl_entities is now dynamically allocated
|
||||||
cl_max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS);
|
cl.max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS);
|
||||||
cl_entities = (entity_t *) Hunk_AllocName (cl_max_edicts*sizeof(entity_t), "cl_entities");
|
cl.entities = (entity_t *) Hunk_AllocName (cl.max_edicts*sizeof(entity_t), "cl_entities");
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
|
||||||
|
cl.viewent.netstate = nullentitystate;
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
PScript_Shutdown();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -132,7 +163,12 @@ void CL_Disconnect (void)
|
||||||
cls.demoplayback = cls.timedemo = false;
|
cls.demoplayback = cls.timedemo = false;
|
||||||
cls.demopaused = false;
|
cls.demopaused = false;
|
||||||
cls.signon = 0;
|
cls.signon = 0;
|
||||||
|
if (cls.download.file)
|
||||||
|
fclose(cls.download.file);
|
||||||
|
memset(&cls.download, 0, sizeof(cls.download));
|
||||||
cl.intermission = 0;
|
cl.intermission = 0;
|
||||||
|
cl.worldmodel = NULL;
|
||||||
|
cl.sendprespawn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CL_Disconnect_f (void)
|
void CL_Disconnect_f (void)
|
||||||
|
@ -152,11 +188,20 @@ Host should be either "local" or a net address to be passed on
|
||||||
*/
|
*/
|
||||||
void CL_EstablishConnection (const char *host)
|
void CL_EstablishConnection (const char *host)
|
||||||
{
|
{
|
||||||
|
static char lasthost[NET_NAMELEN];
|
||||||
if (cls.state == ca_dedicated)
|
if (cls.state == ca_dedicated)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (cls.demoplayback)
|
if (cls.demoplayback)
|
||||||
return;
|
return;
|
||||||
|
if (!host)
|
||||||
|
{
|
||||||
|
host = lasthost;
|
||||||
|
if (!*host)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
q_strlcpy(lasthost, host, sizeof(lasthost));
|
||||||
|
|
||||||
CL_Disconnect ();
|
CL_Disconnect ();
|
||||||
|
|
||||||
|
@ -188,12 +233,12 @@ void CL_SignonReply (void)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
MSG_WriteByte (&cls.message, clc_stringcmd);
|
MSG_WriteByte (&cls.message, clc_stringcmd);
|
||||||
MSG_WriteString (&cls.message, "prespawn");
|
MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
|
||||||
|
|
||||||
|
cl.sendprespawn = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
MSG_WriteByte (&cls.message, clc_stringcmd);
|
|
||||||
MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
|
|
||||||
|
|
||||||
MSG_WriteByte (&cls.message, clc_stringcmd);
|
MSG_WriteByte (&cls.message, clc_stringcmd);
|
||||||
MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));
|
MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));
|
||||||
|
@ -261,7 +306,7 @@ void CL_PrintEntities_f (void)
|
||||||
if (cls.state != ca_connected)
|
if (cls.state != ca_connected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)
|
for (i=0,ent=cl.entities ; i<cl.num_entities ; i++,ent++)
|
||||||
{
|
{
|
||||||
Con_Printf ("%3i:",i);
|
Con_Printf ("%3i:",i);
|
||||||
if (!ent->model)
|
if (!ent->model)
|
||||||
|
@ -398,6 +443,120 @@ float CL_LerpPoint (void)
|
||||||
return frac;
|
return frac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static qboolean CL_LerpEntity(entity_t *ent, vec3_t org, vec3_t ang, float frac)
|
||||||
|
{
|
||||||
|
float f, d;
|
||||||
|
int j;
|
||||||
|
vec3_t delta;
|
||||||
|
qboolean teleported = false;
|
||||||
|
//figure out the pos+angles of the parent
|
||||||
|
if (ent->forcelink)
|
||||||
|
{ // the entity was not updated in the last message
|
||||||
|
// so move to the final spot
|
||||||
|
VectorCopy (ent->msg_origins[0], org);
|
||||||
|
VectorCopy (ent->msg_angles[0], ang);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // if the delta is large, assume a teleport and don't lerp
|
||||||
|
f = frac;
|
||||||
|
for (j=0 ; j<3 ; j++)
|
||||||
|
{
|
||||||
|
delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];
|
||||||
|
if (delta[j] > 100 || delta[j] < -100)
|
||||||
|
{
|
||||||
|
f = 1; // assume a teleportation, not a motion
|
||||||
|
teleported = true; //johnfitz -- don't lerp teleports
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//johnfitz -- don't cl_lerp entities that will be r_lerped
|
||||||
|
if (r_lerpmove.value && (ent->lerpflags & LERP_MOVESTEP))
|
||||||
|
f = 1;
|
||||||
|
//johnfitz
|
||||||
|
|
||||||
|
// interpolate the origin and angles
|
||||||
|
for (j=0 ; j<3 ; j++)
|
||||||
|
{
|
||||||
|
org[j] = ent->msg_origins[1][j] + f*delta[j];
|
||||||
|
|
||||||
|
d = ent->msg_angles[0][j] - ent->msg_angles[1][j];
|
||||||
|
if (d > 180)
|
||||||
|
d -= 360;
|
||||||
|
else if (d < -180)
|
||||||
|
d += 360;
|
||||||
|
ang[j] = ent->msg_angles[1][j] + f*d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return teleported;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean CL_AttachEntity(entity_t *ent, float frac)
|
||||||
|
{
|
||||||
|
entity_t *parent;
|
||||||
|
vec3_t porg, pang;
|
||||||
|
vec3_t paxis[3];
|
||||||
|
vec3_t tmp, fwd, up;
|
||||||
|
unsigned int tagent = ent->netstate.tagentity;
|
||||||
|
int runaway = 0;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
if (!tagent)
|
||||||
|
return true; //nothing to do.
|
||||||
|
if (runaway++==10 || tagent >= (unsigned int)cl.num_entities)
|
||||||
|
return false; //parent isn't valid
|
||||||
|
parent = &cl.entities[tagent];
|
||||||
|
if (!parent->model)
|
||||||
|
return false;
|
||||||
|
if (0)//tagent < ent-cl_entities)
|
||||||
|
{
|
||||||
|
tagent = parent->netstate.tagentity;
|
||||||
|
VectorCopy(parent->origin, porg);
|
||||||
|
VectorCopy(parent->angles, pang);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tagent = parent->netstate.tagentity;
|
||||||
|
CL_LerpEntity(parent, porg, pang, frac);
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: this code needs to know the exact lerp info of the underlaying model.
|
||||||
|
//however for some idiotic reason, someone decided to figure out what should be displayed somewhere far removed from the code that deals with timing
|
||||||
|
//so we have absolutely no way to get a reliable origin
|
||||||
|
//in the meantime, r_lerpmove 0; r_lerpmodels 0
|
||||||
|
//you might be able to work around it by setting the attached entity to movetype_step to match the attachee, and to avoid EF_MUZZLEFLASH.
|
||||||
|
//personally I'm just going to call it a quakespasm bug that I cba to fix.
|
||||||
|
|
||||||
|
//FIXME: update porg+pang according to the tag index (we don't support md3s/iqms, so we don't need to do anything here yet)
|
||||||
|
|
||||||
|
if (parent->model && parent->model->type == mod_alias)
|
||||||
|
pang[0] *= -1;
|
||||||
|
AngleVectors(pang, paxis[0], paxis[1], paxis[2]);
|
||||||
|
|
||||||
|
if (ent->model && ent->model->type == mod_alias)
|
||||||
|
ent->angles[0] *= -1;
|
||||||
|
AngleVectors(ent->angles, fwd, tmp, up);
|
||||||
|
|
||||||
|
//transform the origin
|
||||||
|
VectorMA(parent->origin, ent->origin[0], paxis[0], tmp);
|
||||||
|
VectorMA(tmp, -ent->origin[1], paxis[1], tmp);
|
||||||
|
VectorMA(tmp, ent->origin[2], paxis[2], ent->origin);
|
||||||
|
|
||||||
|
//transform the forward vector
|
||||||
|
VectorMA(vec3_origin, fwd[0], paxis[0], tmp);
|
||||||
|
VectorMA(tmp, -fwd[1], paxis[1], tmp);
|
||||||
|
VectorMA(tmp, fwd[2], paxis[2], fwd);
|
||||||
|
//transform the up vector
|
||||||
|
VectorMA(vec3_origin, up[0], paxis[0], tmp);
|
||||||
|
VectorMA(tmp, -up[1], paxis[1], tmp);
|
||||||
|
VectorMA(tmp, up[2], paxis[2], up);
|
||||||
|
//regenerate the new angles.
|
||||||
|
VectorAngles(fwd, up, ent->angles);
|
||||||
|
if (ent->model && ent->model->type == mod_alias)
|
||||||
|
ent->angles[0] *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
CL_RelinkEntities
|
CL_RelinkEntities
|
||||||
|
@ -407,15 +566,27 @@ void CL_RelinkEntities (void)
|
||||||
{
|
{
|
||||||
entity_t *ent;
|
entity_t *ent;
|
||||||
int i, j;
|
int i, j;
|
||||||
float frac, f, d;
|
float frac, d;
|
||||||
vec3_t delta;
|
|
||||||
float bobjrotate;
|
float bobjrotate;
|
||||||
vec3_t oldorg;
|
vec3_t oldorg;
|
||||||
dlight_t *dl;
|
dlight_t *dl;
|
||||||
|
float frametime;
|
||||||
|
int modelflags;
|
||||||
|
|
||||||
// determine partial update time
|
// determine partial update time
|
||||||
frac = CL_LerpPoint ();
|
frac = CL_LerpPoint ();
|
||||||
|
|
||||||
|
frametime = cl.time - cl.oldtime;
|
||||||
|
if (frametime < 0)
|
||||||
|
frametime = 0;
|
||||||
|
if (frametime > 0.1)
|
||||||
|
frametime = 0.1;
|
||||||
|
|
||||||
|
if (cl_numvisedicts + 64 > cl_maxvisedicts)
|
||||||
|
{
|
||||||
|
cl_maxvisedicts = cl_maxvisedicts+64;
|
||||||
|
cl_visedicts = realloc(cl_visedicts, sizeof(*cl_visedicts)*cl_maxvisedicts);
|
||||||
|
}
|
||||||
cl_numvisedicts = 0;
|
cl_numvisedicts = 0;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -442,10 +613,10 @@ void CL_RelinkEntities (void)
|
||||||
bobjrotate = anglemod(100*cl.time);
|
bobjrotate = anglemod(100*cl.time);
|
||||||
|
|
||||||
// start on the entity after the world
|
// start on the entity after the world
|
||||||
for (i=1,ent=cl_entities+1 ; i<cl.num_entities ; i++,ent++)
|
for (i=1,ent=cl.entities+1 ; i<cl.num_entities ; i++,ent++)
|
||||||
{
|
{
|
||||||
if (!ent->model)
|
if (!ent->model)
|
||||||
{ // empty slot
|
{ // empty slot, ish.
|
||||||
|
|
||||||
// ericw -- efrags are only used for static entities in GLQuake
|
// ericw -- efrags are only used for static entities in GLQuake
|
||||||
// ent can't be static, so this is a no-op.
|
// ent can't be static, so this is a no-op.
|
||||||
|
@ -464,46 +635,22 @@ void CL_RelinkEntities (void)
|
||||||
|
|
||||||
VectorCopy (ent->origin, oldorg);
|
VectorCopy (ent->origin, oldorg);
|
||||||
|
|
||||||
if (ent->forcelink)
|
if (CL_LerpEntity(ent, ent->origin, ent->angles, frac))
|
||||||
{ // the entity was not updated in the last message
|
ent->lerpflags |= LERP_RESETMOVE;
|
||||||
// so move to the final spot
|
|
||||||
VectorCopy (ent->msg_origins[0], ent->origin);
|
if (ent->netstate.tagentity)
|
||||||
VectorCopy (ent->msg_angles[0], ent->angles);
|
if (!CL_AttachEntity(ent, frac))
|
||||||
|
{
|
||||||
|
//can't draw it if we don't know where its parent is.
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ // if the delta is large, assume a teleport and don't lerp
|
|
||||||
f = frac;
|
|
||||||
for (j=0 ; j<3 ; j++)
|
|
||||||
{
|
|
||||||
delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];
|
|
||||||
if (delta[j] > 100 || delta[j] < -100)
|
|
||||||
{
|
|
||||||
f = 1; // assume a teleportation, not a motion
|
|
||||||
ent->lerpflags |= LERP_RESETMOVE; //johnfitz -- don't lerp teleports
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//johnfitz -- don't cl_lerp entities that will be r_lerped
|
modelflags = (ent->effects>>24)&0xff;
|
||||||
if (r_lerpmove.value && (ent->lerpflags & LERP_MOVESTEP))
|
if (!(ent->effects & EF_NOMODELFLAGS))
|
||||||
f = 1;
|
modelflags |= ent->model->flags;
|
||||||
//johnfitz
|
|
||||||
|
|
||||||
// interpolate the origin and angles
|
|
||||||
for (j=0 ; j<3 ; j++)
|
|
||||||
{
|
|
||||||
ent->origin[j] = ent->msg_origins[1][j] + f*delta[j];
|
|
||||||
|
|
||||||
d = ent->msg_angles[0][j] - ent->msg_angles[1][j];
|
|
||||||
if (d > 180)
|
|
||||||
d -= 360;
|
|
||||||
else if (d < -180)
|
|
||||||
d += 360;
|
|
||||||
ent->angles[j] = ent->msg_angles[1][j] + f*d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotate binary objects locally
|
// rotate binary objects locally
|
||||||
if (ent->model->flags & EF_ROTATE)
|
if (modelflags & EF_ROTATE)
|
||||||
ent->angles[1] = bobjrotate;
|
ent->angles[1] = bobjrotate;
|
||||||
|
|
||||||
if (ent->effects & EF_BRIGHTFIELD)
|
if (ent->effects & EF_BRIGHTFIELD)
|
||||||
|
@ -526,10 +673,10 @@ void CL_RelinkEntities (void)
|
||||||
//johnfitz -- assume muzzle flash accompanied by muzzle flare, which looks bad when lerped
|
//johnfitz -- assume muzzle flash accompanied by muzzle flare, which looks bad when lerped
|
||||||
if (r_lerpmodels.value != 2)
|
if (r_lerpmodels.value != 2)
|
||||||
{
|
{
|
||||||
if (ent == &cl_entities[cl.viewentity])
|
if (ent == &cl.entities[cl.viewentity])
|
||||||
cl.viewent.lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames
|
cl.viewent.lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames
|
||||||
else
|
else
|
||||||
ent->lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames
|
ent->lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames
|
||||||
}
|
}
|
||||||
//johnfitz
|
//johnfitz
|
||||||
}
|
}
|
||||||
|
@ -549,33 +696,95 @@ void CL_RelinkEntities (void)
|
||||||
dl->die = cl.time + 0.001;
|
dl->die = cl.time + 0.001;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ent->model->flags & EF_GIB)
|
#ifdef PSET_SCRIPT
|
||||||
R_RocketTrail (oldorg, ent->origin, 2);
|
if (cl.paused)
|
||||||
else if (ent->model->flags & EF_ZOMGIB)
|
;
|
||||||
R_RocketTrail (oldorg, ent->origin, 4);
|
else if (ent->netstate.traileffectnum > 0 && ent->netstate.traileffectnum < MAX_PARTICLETYPES)
|
||||||
else if (ent->model->flags & EF_TRACER)
|
|
||||||
R_RocketTrail (oldorg, ent->origin, 3);
|
|
||||||
else if (ent->model->flags & EF_TRACER2)
|
|
||||||
R_RocketTrail (oldorg, ent->origin, 5);
|
|
||||||
else if (ent->model->flags & EF_ROCKET)
|
|
||||||
{
|
{
|
||||||
R_RocketTrail (oldorg, ent->origin, 0);
|
vec3_t axis[3];
|
||||||
|
AngleVectors(ent->angles, axis[0], axis[1], axis[2]);
|
||||||
|
PScript_ParticleTrail(oldorg, ent->origin, cl.particle_precache[ent->netstate.traileffectnum].index, i, axis, &ent->trailstate);
|
||||||
|
}
|
||||||
|
else if (ent->model->traileffect >= 0)
|
||||||
|
{
|
||||||
|
vec3_t axis[3];
|
||||||
|
AngleVectors(ent->angles, axis[0], axis[1], axis[2]);
|
||||||
|
PScript_ParticleTrail(oldorg, ent->origin, ent->model->traileffect, i, axis, &ent->trailstate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (modelflags & EF_GIB)
|
||||||
|
{
|
||||||
|
if (PScript_EntParticleTrail(oldorg, ent, "TR_BLOOD"))
|
||||||
|
R_RocketTrail (oldorg, ent->origin, 2);
|
||||||
|
}
|
||||||
|
else if (modelflags & EF_ZOMGIB)
|
||||||
|
{
|
||||||
|
if (PScript_EntParticleTrail(oldorg, ent, "TR_SLIGHTBLOOD"))
|
||||||
|
R_RocketTrail (oldorg, ent->origin, 4);
|
||||||
|
}
|
||||||
|
else if (modelflags & EF_TRACER)
|
||||||
|
{
|
||||||
|
if (PScript_EntParticleTrail(oldorg, ent, "TR_WIZSPIKE"))
|
||||||
|
R_RocketTrail (oldorg, ent->origin, 3);
|
||||||
|
}
|
||||||
|
else if (modelflags & EF_TRACER2)
|
||||||
|
{
|
||||||
|
if (PScript_EntParticleTrail(oldorg, ent, "TR_KNIGHTSPIKE"))
|
||||||
|
R_RocketTrail (oldorg, ent->origin, 5);
|
||||||
|
}
|
||||||
|
else if (modelflags & EF_ROCKET)
|
||||||
|
{
|
||||||
|
if (PScript_EntParticleTrail(oldorg, ent, "TR_ROCKET"))
|
||||||
|
R_RocketTrail (oldorg, ent->origin, 0);
|
||||||
dl = CL_AllocDlight (i);
|
dl = CL_AllocDlight (i);
|
||||||
VectorCopy (ent->origin, dl->origin);
|
VectorCopy (ent->origin, dl->origin);
|
||||||
dl->radius = 200;
|
dl->radius = 200;
|
||||||
dl->die = cl.time + 0.01;
|
dl->die = cl.time + 0.01;
|
||||||
}
|
}
|
||||||
else if (ent->model->flags & EF_GRENADE)
|
else if (modelflags & EF_GRENADE)
|
||||||
R_RocketTrail (oldorg, ent->origin, 1);
|
{
|
||||||
else if (ent->model->flags & EF_TRACER3)
|
if (PScript_EntParticleTrail(oldorg, ent, "TR_GRENADE"))
|
||||||
R_RocketTrail (oldorg, ent->origin, 6);
|
R_RocketTrail (oldorg, ent->origin, 1);
|
||||||
|
}
|
||||||
|
else if (modelflags & EF_TRACER3)
|
||||||
|
{
|
||||||
|
if (PScript_EntParticleTrail(oldorg, ent, "TR_VORESPIKE"))
|
||||||
|
R_RocketTrail (oldorg, ent->origin, 6);
|
||||||
|
}
|
||||||
|
|
||||||
ent->forcelink = false;
|
ent->forcelink = false;
|
||||||
|
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
if (ent->netstate.emiteffectnum > 0)
|
||||||
|
{
|
||||||
|
vec3_t axis[3];
|
||||||
|
AngleVectors(ent->angles, axis[0], axis[1], axis[2]);
|
||||||
|
if (ent->model->type == mod_alias)
|
||||||
|
axis[0][2] *= -1; //stupid vanilla bug
|
||||||
|
PScript_RunParticleEffectState(ent->origin, axis[0], frametime, cl.particle_precache[ent->netstate.emiteffectnum].index, &ent->emitstate);
|
||||||
|
}
|
||||||
|
else if (ent->model->emiteffect >= 0)
|
||||||
|
{
|
||||||
|
vec3_t axis[3];
|
||||||
|
AngleVectors(ent->angles, axis[0], axis[1], axis[2]);
|
||||||
|
if (ent->model->flags & MOD_EMITFORWARDS)
|
||||||
|
{
|
||||||
|
if (ent->model->type == mod_alias)
|
||||||
|
axis[0][2] *= -1; //stupid vanilla bug
|
||||||
|
}
|
||||||
|
else
|
||||||
|
VectorScale(axis[2], -1, axis[0]);
|
||||||
|
PScript_RunParticleEffectState(ent->origin, axis[0], frametime, ent->model->emiteffect, &ent->emitstate);
|
||||||
|
if (ent->model->flags & MOD_EMITREPLACE)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (i == cl.viewentity && !chase_active.value)
|
if (i == cl.viewentity && !chase_active.value)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (cl_numvisedicts < MAX_VISEDICTS)
|
if (cl_numvisedicts < cl_maxvisedicts)
|
||||||
{
|
{
|
||||||
cl_visedicts[cl_numvisedicts] = ent;
|
cl_visedicts[cl_numvisedicts] = ent;
|
||||||
cl_numvisedicts++;
|
cl_numvisedicts++;
|
||||||
|
@ -583,6 +792,248 @@ void CL_RelinkEntities (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
int CL_GenerateRandomParticlePrecache(const char *pname)
|
||||||
|
{ //for dpp7 compat
|
||||||
|
size_t i;
|
||||||
|
pname = va("%s", pname);
|
||||||
|
for (i = 1; i < MAX_PARTICLETYPES; i++)
|
||||||
|
{
|
||||||
|
if (!cl.particle_precache[i].name)
|
||||||
|
{
|
||||||
|
cl.particle_precache[i].name = strcpy(Hunk_Alloc(strlen(pname)+1), pname);
|
||||||
|
cl.particle_precache[i].index = PScript_FindParticleType(cl.particle_precache[i].name);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
if (!strcmp(cl.particle_precache[i].name, pname))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//sent by the server to let us know that dp downloads can be used
|
||||||
|
void CL_ServerExtension_Download_f(void)
|
||||||
|
{
|
||||||
|
if (Cmd_Argc() == 2)
|
||||||
|
cl.protocol_dpdownload = atoi(Cmd_Argv(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
//sent by the server to let us know when its finished sending the entire file
|
||||||
|
void CL_Download_Finished_f(void)
|
||||||
|
{
|
||||||
|
if (cls.download.file)
|
||||||
|
{
|
||||||
|
char finalpath[MAX_OSPATH];
|
||||||
|
unsigned int size = strtoul(Cmd_Argv(1), NULL, 0);
|
||||||
|
unsigned int hash = strtoul(Cmd_Argv(2), NULL, 0);
|
||||||
|
//const char *fname = Cmd_Argv(3);
|
||||||
|
qboolean hashokay = false;
|
||||||
|
if (size == cls.download.size)
|
||||||
|
{
|
||||||
|
byte *tmp = malloc(size);
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
fseek(cls.download.file, 0, SEEK_SET);
|
||||||
|
fread(tmp, 1, size, cls.download.file);
|
||||||
|
hashokay = (hash == CRC_Block(tmp, size));
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
if (!hashokay) Con_Warning("Download hash failure\n");
|
||||||
|
}
|
||||||
|
else Con_Warning("Download size too large\n");
|
||||||
|
}
|
||||||
|
else Con_Warning("Download size mismatch\n");
|
||||||
|
|
||||||
|
fclose(cls.download.file);
|
||||||
|
cls.download.file = NULL;
|
||||||
|
if (hashokay)
|
||||||
|
{
|
||||||
|
q_snprintf (finalpath, sizeof(finalpath), "%s/%s", com_gamedir, cls.download.current);
|
||||||
|
rename(cls.download.temp, finalpath);
|
||||||
|
Con_SafePrintf("Downloaded %s: %u bytes\n", cls.download.current, cls.download.size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Warning("Download of %s failed\n", cls.download.current);
|
||||||
|
unlink(cls.download.temp); //kill the temp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.download.active = false;
|
||||||
|
}
|
||||||
|
//sent by the server (or issued by the user) to stop the current download for any reason.
|
||||||
|
void CL_StopDownload_f(void)
|
||||||
|
{
|
||||||
|
if (cls.download.file)
|
||||||
|
{
|
||||||
|
fclose(cls.download.file);
|
||||||
|
cls.download.file = NULL;
|
||||||
|
unlink(cls.download.temp);
|
||||||
|
|
||||||
|
// Con_SafePrintf("Download cancelled\n", cl.download_current, cl.download_size);
|
||||||
|
}
|
||||||
|
cls.download.active = false;
|
||||||
|
}
|
||||||
|
//sent by the server to let us know that its going to start spamming us now.
|
||||||
|
void CL_Download_Begin_f(void)
|
||||||
|
{
|
||||||
|
if (!cls.download.active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cls.download.file)
|
||||||
|
CL_StopDownload_f();
|
||||||
|
|
||||||
|
//cl_downloadbegin size "name"
|
||||||
|
cls.download.size = strtoul(Cmd_Argv(1), NULL, 0);
|
||||||
|
|
||||||
|
COM_CreatePath(cls.download.temp);
|
||||||
|
cls.download.file = fopen(cls.download.temp, "wb+"); //+ so we can read the data back to validate it
|
||||||
|
|
||||||
|
MSG_WriteByte (&cls.message, clc_stringcmd);
|
||||||
|
MSG_WriteString (&cls.message, "sv_startdownload\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CL_Download_Data(void)
|
||||||
|
{
|
||||||
|
byte *data;
|
||||||
|
unsigned int start, size;
|
||||||
|
start = MSG_ReadLong();
|
||||||
|
size = (unsigned short)MSG_ReadShort();
|
||||||
|
data = MSG_ReadData(size);
|
||||||
|
if (msg_badread)
|
||||||
|
return;
|
||||||
|
if (!cls.download.file)
|
||||||
|
return; //demo started mid-record? something weird anyway
|
||||||
|
|
||||||
|
fseek(cls.download.file, start, SEEK_SET);
|
||||||
|
fwrite(data, 1, size, cls.download.file);
|
||||||
|
|
||||||
|
Con_SafePrintf("Downloading %s: %g%%\r", cls.download.current, 100*(start+size) / (double)cls.download.size);
|
||||||
|
|
||||||
|
//should maybe use unreliables, but whatever, shouldn't matter too much, it'll still complete
|
||||||
|
MSG_WriteByte(&cls.message, clcdp_ackdownloaddata);
|
||||||
|
MSG_WriteLong(&cls.message, start);
|
||||||
|
MSG_WriteShort(&cls.message, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns true if we should block waiting for a download, false if there's no point.
|
||||||
|
qboolean CL_CheckDownload(const char *filename)
|
||||||
|
{
|
||||||
|
if (sv.active)
|
||||||
|
return false; //no point downloading if we're the server...
|
||||||
|
if (*filename == '*')
|
||||||
|
return false; //don't download these...
|
||||||
|
if (cls.download.active)
|
||||||
|
return true; //block while we're already downloading something
|
||||||
|
if (!cl.protocol_dpdownload)
|
||||||
|
return false; //can't download anyway
|
||||||
|
if (*cls.download.current && !strcmp(cls.download.current, filename))
|
||||||
|
return false; //if the previous download failed, don't endlessly retry.
|
||||||
|
if (COM_FileExists(filename, NULL))
|
||||||
|
return false; //no need to download anything.
|
||||||
|
if (!COM_DownloadNameOkay(filename))
|
||||||
|
return false; //diediedie
|
||||||
|
|
||||||
|
cls.download.active = true;
|
||||||
|
q_strlcpy(cls.download.current, filename, sizeof(cls.download.current));
|
||||||
|
q_snprintf (cls.download.temp, sizeof(cls.download.temp), "%s/%s.tmp", com_gamedir, filename);
|
||||||
|
Con_Printf("Downloading %s...\r", filename);
|
||||||
|
MSG_WriteByte (&cls.message, clc_stringcmd);
|
||||||
|
MSG_WriteString (&cls.message, va("download \"%s\"\n", filename));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//download+load models and sounds as needed, once complete let the server know we're ready for the next stage.
|
||||||
|
//returning false will trigger nops.
|
||||||
|
qboolean CL_CheckDownloads(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (cl.model_download == 0 && cl.model_count && cl.model_name[1])
|
||||||
|
{ //haxors, download the lit first, but only if we don't already have the bsp
|
||||||
|
//this ensures that we don't keep requesting the lit for maps that just don't have one (although may be problematic if the first server we find deleted them all, but oh well)
|
||||||
|
char litname[MAX_QPATH];
|
||||||
|
char *ext;
|
||||||
|
q_strlcpy(litname, cl.model_name[1], sizeof(litname));
|
||||||
|
ext = (char*)COM_FileGetExtension(litname);
|
||||||
|
if (!q_strcasecmp(ext, "bsp"))
|
||||||
|
{
|
||||||
|
if (!COM_FileExists(litname, NULL))
|
||||||
|
{
|
||||||
|
strcpy(ext, "lit");
|
||||||
|
if (CL_CheckDownload(litname))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cl.model_download++;
|
||||||
|
}
|
||||||
|
for (; cl.model_download < cl.model_count; )
|
||||||
|
{
|
||||||
|
if (*cl.model_name[cl.model_download])
|
||||||
|
{
|
||||||
|
if (CL_CheckDownload(cl.model_name[cl.model_download]))
|
||||||
|
return false;
|
||||||
|
cl.model_precache[cl.model_download] = Mod_ForName (cl.model_name[cl.model_download], false);
|
||||||
|
if (cl.model_precache[cl.model_download] == NULL)
|
||||||
|
{
|
||||||
|
Host_Error ("Model %s not found", cl.model_name[cl.model_download]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cl.model_download++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; cl.sound_download < cl.sound_count; )
|
||||||
|
{
|
||||||
|
if (*cl.sound_name[cl.sound_download])
|
||||||
|
{
|
||||||
|
if (CL_CheckDownload(va("sound/%s", cl.sound_name[cl.sound_download])))
|
||||||
|
return false;
|
||||||
|
cl.sound_precache[cl.sound_download] = S_PrecacheSound (cl.sound_name[cl.sound_download]);
|
||||||
|
}
|
||||||
|
cl.sound_download++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cl.worldmodel && cl.model_count >= 2)
|
||||||
|
{
|
||||||
|
// local state
|
||||||
|
cl.entities[0].model = cl.worldmodel = cl.model_precache[1];
|
||||||
|
if (cl.worldmodel->type != mod_brush)
|
||||||
|
{
|
||||||
|
if (cl.worldmodel->type == mod_ext_invalid)
|
||||||
|
Host_Error ("Worldmodel %s was not loaded", cl.model_name[1]);
|
||||||
|
else
|
||||||
|
Host_Error ("Worldmodel %s is not a brushmodel", cl.model_name[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//fixme: deal with skybox somehow
|
||||||
|
|
||||||
|
R_NewMap ();
|
||||||
|
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
//the protocol changing depending upon files found on the client's computer is of course a really shit way to design things
|
||||||
|
//especially when users have a nasty habit of changing config files.
|
||||||
|
if (cl.protocol == PROTOCOL_VERSION_DP7)
|
||||||
|
{
|
||||||
|
PScript_FindParticleType("effectinfo."); //make sure this is implicitly loaded.
|
||||||
|
COM_Effectinfo_Enumerate(CL_GenerateRandomParticlePrecache);
|
||||||
|
cl.protocol_particles = true;
|
||||||
|
}
|
||||||
|
else if (cl.protocol_pext2)
|
||||||
|
cl.protocol_particles = true; //doesn't have a pext flag of its own, but at least we know what it is.
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//make sure ents have the correct models, now that they're actually loaded.
|
||||||
|
for (i = 0; i < cl.num_statics; i++)
|
||||||
|
{
|
||||||
|
if (cl.static_entities[i]->model)
|
||||||
|
continue;
|
||||||
|
cl.static_entities[i]->model = cl.model_precache[cl.static_entities[i]->netstate.modelindex];
|
||||||
|
R_AddEfrags (cl.static_entities[i]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
|
@ -627,7 +1078,7 @@ int CL_ReadFromServer (void)
|
||||||
|
|
||||||
//visedicts
|
//visedicts
|
||||||
if (cl_numvisedicts > 256 && dev_peakstats.visedicts <= 256)
|
if (cl_numvisedicts > 256 && dev_peakstats.visedicts <= 256)
|
||||||
Con_DWarning ("%i visedicts exceeds standard limit of 256 (max = %d).\n", cl_numvisedicts, MAX_VISEDICTS);
|
Con_DWarning ("%i visedicts exceeds standard limit of 256.\n", cl_numvisedicts);
|
||||||
dev_stats.visedicts = cl_numvisedicts;
|
dev_stats.visedicts = cl_numvisedicts;
|
||||||
dev_peakstats.visedicts = q_max(cl_numvisedicts, dev_peakstats.visedicts);
|
dev_peakstats.visedicts = q_max(cl_numvisedicts, dev_peakstats.visedicts);
|
||||||
|
|
||||||
|
@ -686,6 +1137,8 @@ void CL_SendCmd (void)
|
||||||
// send the unreliable message
|
// send the unreliable message
|
||||||
CL_SendMove (&cmd);
|
CL_SendMove (&cmd);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
CL_SendMove (NULL);
|
||||||
|
|
||||||
if (cls.demoplayback)
|
if (cls.demoplayback)
|
||||||
{
|
{
|
||||||
|
@ -755,15 +1208,30 @@ void CL_Viewpos_f (void)
|
||||||
#else
|
#else
|
||||||
//player position
|
//player position
|
||||||
Con_Printf ("Viewpos: (%i %i %i) %i %i %i\n",
|
Con_Printf ("Viewpos: (%i %i %i) %i %i %i\n",
|
||||||
(int)cl_entities[cl.viewentity].origin[0],
|
(int)cl.entities[cl.viewentity].origin[0],
|
||||||
(int)cl_entities[cl.viewentity].origin[1],
|
(int)cl.entities[cl.viewentity].origin[1],
|
||||||
(int)cl_entities[cl.viewentity].origin[2],
|
(int)cl.entities[cl.viewentity].origin[2],
|
||||||
(int)cl.viewangles[PITCH],
|
(int)cl.viewangles[PITCH],
|
||||||
(int)cl.viewangles[YAW],
|
(int)cl.viewangles[YAW],
|
||||||
(int)cl.viewangles[ROLL]);
|
(int)cl.viewangles[ROLL]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CL_ServerExtension_FullServerinfo_f(void)
|
||||||
|
{
|
||||||
|
// const char *newserverinfo = Cmd_Argv(1);
|
||||||
|
}
|
||||||
|
static void CL_ServerExtension_ServerinfoUpdate_f(void)
|
||||||
|
{
|
||||||
|
// const char *newserverkey = Cmd_Argv(1);
|
||||||
|
// const char *newservervalue = Cmd_Argv(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CL_ServerExtension_Ignore_f(void)
|
||||||
|
{
|
||||||
|
Con_DPrintf2("Ignoring stufftext: %s\n", Cmd_Argv(0));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
CL_Init
|
CL_Init
|
||||||
|
@ -803,6 +1271,7 @@ void CL_Init (void)
|
||||||
|
|
||||||
Cvar_RegisterVariable (&cl_maxpitch); //johnfitz -- variable pitch clamping
|
Cvar_RegisterVariable (&cl_maxpitch); //johnfitz -- variable pitch clamping
|
||||||
Cvar_RegisterVariable (&cl_minpitch); //johnfitz -- variable pitch clamping
|
Cvar_RegisterVariable (&cl_minpitch); //johnfitz -- variable pitch clamping
|
||||||
|
Cvar_RegisterVariable (&cl_recordingdemo); //spike -- for mod hacks. combine with cvar_string or something
|
||||||
|
|
||||||
Cmd_AddCommand ("entities", CL_PrintEntities_f);
|
Cmd_AddCommand ("entities", CL_PrintEntities_f);
|
||||||
Cmd_AddCommand ("disconnect", CL_Disconnect_f);
|
Cmd_AddCommand ("disconnect", CL_Disconnect_f);
|
||||||
|
@ -813,5 +1282,27 @@ void CL_Init (void)
|
||||||
|
|
||||||
Cmd_AddCommand ("tracepos", CL_Tracepos_f); //johnfitz
|
Cmd_AddCommand ("tracepos", CL_Tracepos_f); //johnfitz
|
||||||
Cmd_AddCommand ("viewpos", CL_Viewpos_f); //johnfitz
|
Cmd_AddCommand ("viewpos", CL_Viewpos_f); //johnfitz
|
||||||
|
|
||||||
|
//spike -- add stubs to mute various invalid stuffcmds
|
||||||
|
Cmd_AddCommand_ServerCommand ("fullserverinfo", CL_ServerExtension_FullServerinfo_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("svi", CL_ServerExtension_ServerinfoUpdate_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("paknames", CL_ServerExtension_Ignore_f); //package names in use by the server (including gamedir+extension)
|
||||||
|
Cmd_AddCommand_ServerCommand ("paks", CL_ServerExtension_Ignore_f); //provides hashes to go with the paknames list
|
||||||
|
//Cmd_AddCommand_ServerCommand ("vwep", CL_ServerExtension_Ignore_f); //invalid for nq, provides an alternative list of model precaches for vweps.
|
||||||
|
//Cmd_AddCommand_ServerCommand ("at", CL_ServerExtension_Ignore_f); //invalid for nq, autotrack info for mvds
|
||||||
|
Cmd_AddCommand_ServerCommand ("wps", CL_ServerExtension_Ignore_f); //ktx/cspree weapon stats
|
||||||
|
Cmd_AddCommand_ServerCommand ("it", CL_ServerExtension_Ignore_f); //cspree item timers
|
||||||
|
Cmd_AddCommand_ServerCommand ("tinfo", CL_ServerExtension_Ignore_f); //ktx team info
|
||||||
|
Cmd_AddCommand_ServerCommand ("exectrigger", CL_ServerExtension_Ignore_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("csqc_progname", CL_ServerExtension_Ignore_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("csqc_progsize", CL_ServerExtension_Ignore_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("csqc_progcrc", CL_ServerExtension_Ignore_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("cl_fullpitch", CL_ServerExtension_Ignore_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("pq_fullpitch", CL_ServerExtension_Ignore_f); //spike
|
||||||
|
|
||||||
|
Cmd_AddCommand_ServerCommand ("cl_serverextension_download", CL_ServerExtension_Download_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("cl_downloadbegin", CL_Download_Begin_f); //spike
|
||||||
|
Cmd_AddCommand_ServerCommand ("cl_downloadfinished", CL_Download_Finished_f); //spike
|
||||||
|
Cmd_AddCommand ("stopdownload", CL_StopDownload_f); //spike
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1845
Quake/cl_parse.c
1845
Quake/cl_parse.c
File diff suppressed because it is too large
Load Diff
285
Quake/cl_tent.c
285
Quake/cl_tent.c
|
@ -56,7 +56,7 @@ void CL_InitTEnts (void)
|
||||||
CL_ParseBeam
|
CL_ParseBeam
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void CL_ParseBeam (qmodel_t *m)
|
void CL_ParseBeam (qmodel_t *m, const char *trailname, const char *impactname)
|
||||||
{
|
{
|
||||||
int ent;
|
int ent;
|
||||||
vec3_t start, end;
|
vec3_t start, end;
|
||||||
|
@ -73,12 +73,24 @@ void CL_ParseBeam (qmodel_t *m)
|
||||||
end[1] = MSG_ReadCoord (cl.protocolflags);
|
end[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
end[2] = MSG_ReadCoord (cl.protocolflags);
|
end[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
|
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
{
|
||||||
|
vec3_t normal, extra, impact;
|
||||||
|
VectorSubtract(end, start, normal);
|
||||||
|
VectorNormalize(normal);
|
||||||
|
VectorMA(end, 4, normal, extra); //extend the end-point by four
|
||||||
|
if (CL_TraceLine(start, extra, impact, normal, NULL)<1)
|
||||||
|
PScript_RunParticleEffectTypeString(impact, normal, 1, impactname);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// override any beam with the same entity
|
// override any beam with the same entity
|
||||||
for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
|
for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
|
||||||
if (b->entity == ent)
|
if (b->entity == ent)
|
||||||
{
|
{
|
||||||
b->entity = ent;
|
b->entity = ent;
|
||||||
b->model = m;
|
b->model = m;
|
||||||
|
b->trailname = trailname;
|
||||||
b->endtime = cl.time + 0.2;
|
b->endtime = cl.time + 0.2;
|
||||||
VectorCopy (start, b->start);
|
VectorCopy (start, b->start);
|
||||||
VectorCopy (end, b->end);
|
VectorCopy (end, b->end);
|
||||||
|
@ -92,6 +104,7 @@ void CL_ParseBeam (qmodel_t *m)
|
||||||
{
|
{
|
||||||
b->entity = ent;
|
b->entity = ent;
|
||||||
b->model = m;
|
b->model = m;
|
||||||
|
b->trailname = trailname;
|
||||||
b->endtime = cl.time + 0.2;
|
b->endtime = cl.time + 0.2;
|
||||||
VectorCopy (start, b->start);
|
VectorCopy (start, b->start);
|
||||||
VectorCopy (end, b->end);
|
VectorCopy (end, b->end);
|
||||||
|
@ -108,6 +121,15 @@ void CL_ParseBeam (qmodel_t *m)
|
||||||
//johnfitz
|
//johnfitz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CL_SpawnSpriteEffect(vec3_t org/*, vec3_t dir, vec3_t orientationup*/, qmodel_t *model, int startframe, int framecount, float framerate/*, float alpha, float scale, float randspin, float gravity, int traileffect, unsigned int renderflags, int skinnum*/)
|
||||||
|
{
|
||||||
|
if (startframe < 0)
|
||||||
|
startframe = framecount = 0;
|
||||||
|
if (!framecount)
|
||||||
|
framecount = model->numframes;
|
||||||
|
Con_DPrintf("CL_SpawnSpriteEffect: not implemented\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
CL_ParseTEnt
|
CL_ParseTEnt
|
||||||
|
@ -128,7 +150,8 @@ void CL_ParseTEnt (void)
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_RunParticleEffect (pos, vec3_origin, 20, 30);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, "TE_WIZSPIKE"))
|
||||||
|
R_RunParticleEffect (pos, vec3_origin, 20, 30);
|
||||||
S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
|
S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -136,15 +159,18 @@ void CL_ParseTEnt (void)
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_RunParticleEffect (pos, vec3_origin, 226, 20);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, "TE_KNIGHTSPIKE"))
|
||||||
|
R_RunParticleEffect (pos, vec3_origin, 226, 20);
|
||||||
S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
|
S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TEDP_SPIKEQUAD:
|
||||||
case TE_SPIKE: // spike hitting wall
|
case TE_SPIKE: // spike hitting wall
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_RunParticleEffect (pos, vec3_origin, 0, 10);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, (type==TEDP_SPIKEQUAD)?"TE_SPIKEQUAD":"TE_SPIKE"))
|
||||||
|
R_RunParticleEffect (pos, vec3_origin, 0, 10);
|
||||||
if ( rand() % 5 )
|
if ( rand() % 5 )
|
||||||
S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
|
S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
|
||||||
else
|
else
|
||||||
|
@ -158,11 +184,13 @@ void CL_ParseTEnt (void)
|
||||||
S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
|
S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TEDP_SUPERSPIKEQUAD:
|
||||||
case TE_SUPERSPIKE: // super spike hitting wall
|
case TE_SUPERSPIKE: // super spike hitting wall
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_RunParticleEffect (pos, vec3_origin, 0, 20);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, (type==TEDP_SUPERSPIKEQUAD)?"TE_SUPERSPIKEQUAD":"TE_SUPERSPIKE"))
|
||||||
|
R_RunParticleEffect (pos, vec3_origin, 0, 20);
|
||||||
|
|
||||||
if ( rand() % 5 )
|
if ( rand() % 5 )
|
||||||
S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
|
S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
|
||||||
|
@ -178,50 +206,73 @@ void CL_ParseTEnt (void)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TEDP_GUNSHOTQUAD:
|
||||||
|
case TEFTE_GUNSHOT_COUNT: //for compat with qw mods
|
||||||
case TE_GUNSHOT: // bullet hitting wall
|
case TE_GUNSHOT: // bullet hitting wall
|
||||||
|
rnd = 20;
|
||||||
|
if (type == TEFTE_GUNSHOT_COUNT)
|
||||||
|
rnd *= MSG_ReadByte();
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_RunParticleEffect (pos, vec3_origin, 0, 20);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, rnd, (type==TEDP_GUNSHOTQUAD)?"TE_GUNSHOTQUAD":"TE_GUNSHOT"))
|
||||||
|
R_RunParticleEffect (pos, vec3_origin, 0, rnd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TEFTE_EXPLOSION_SPRITE://for compat with qw mods
|
||||||
|
case TEDP_EXPLOSIONQUAD:
|
||||||
|
case TENEH_EXPLOSION3:
|
||||||
case TE_EXPLOSION: // rocket explosion
|
case TE_EXPLOSION: // rocket explosion
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_ParticleExplosion (pos);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, (type==TEDP_EXPLOSIONQUAD)?"TE_EXPLOSIONQUAD":"TE_EXPLOSION"))
|
||||||
|
R_ParticleExplosion (pos);
|
||||||
dl = CL_AllocDlight (0);
|
dl = CL_AllocDlight (0);
|
||||||
VectorCopy (pos, dl->origin);
|
VectorCopy (pos, dl->origin);
|
||||||
dl->radius = 350;
|
dl->radius = 350;
|
||||||
dl->die = cl.time + 0.5;
|
dl->die = cl.time + 0.5;
|
||||||
dl->decay = 300;
|
dl->decay = 300;
|
||||||
|
if (type == TENEH_EXPLOSION3)
|
||||||
|
{ //the *2 is to match dp's expectations, for some reason.
|
||||||
|
dl->color[0] = MSG_ReadCoord(cl.protocolflags)*2.0;
|
||||||
|
dl->color[1] = MSG_ReadCoord(cl.protocolflags)*2.0;
|
||||||
|
dl->color[2] = MSG_ReadCoord(cl.protocolflags)*2.0;
|
||||||
|
}
|
||||||
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
||||||
|
|
||||||
|
if (type==TEFTE_EXPLOSION_SPRITE)
|
||||||
|
{
|
||||||
|
qmodel_t *mod = Mod_ForName ("progs/s_explod.spr", false);
|
||||||
|
CL_SpawnSpriteEffect(pos/*, NULL, NULL*/, mod, 0, 0, 10/*, mod->type==mod_sprite?-1:1, 1, 0, 0, P_INVALID, 0, 0*/);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TE_TAREXPLOSION: // tarbaby explosion
|
case TE_TAREXPLOSION: // tarbaby explosion
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_BlobExplosion (pos);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, "TE_TAREXPLOSION"))
|
||||||
|
R_BlobExplosion (pos);
|
||||||
|
|
||||||
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TE_LIGHTNING1: // lightning bolts
|
case TE_LIGHTNING1: // lightning bolts
|
||||||
CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
|
CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true), "TE_LIGHTNING1", "TE_LIGHTNING1_END");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TE_LIGHTNING2: // lightning bolts
|
case TE_LIGHTNING2: // lightning bolts
|
||||||
CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
|
CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true), "TE_LIGHTNING2", "TE_LIGHTNING2_END");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TE_LIGHTNING3: // lightning bolts
|
case TE_LIGHTNING3: // lightning bolts
|
||||||
CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
|
CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true), "TE_LIGHTNING3", "TE_LIGHTNING3_END");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// PGM 01/21/97
|
// PGM 01/21/97
|
||||||
case TE_BEAM: // grappling hook beam
|
case TE_BEAM: // grappling hook beam
|
||||||
CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
|
CL_ParseBeam (Mod_ForName("progs/beam.mdl", true), "TE_BEAM", "TE_BEAM_END");
|
||||||
break;
|
break;
|
||||||
// PGM 01/21/97
|
// PGM 01/21/97
|
||||||
|
|
||||||
|
@ -229,14 +280,16 @@ void CL_ParseTEnt (void)
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_LavaSplash (pos);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, "TE_LAVASPLASH"))
|
||||||
|
R_LavaSplash (pos);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TE_TELEPORT:
|
case TE_TELEPORT:
|
||||||
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
pos[0] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
pos[1] = MSG_ReadCoord (cl.protocolflags);
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
R_TeleportSplash (pos);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, "TE_TELEPORT"))
|
||||||
|
R_TeleportSplash (pos);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TE_EXPLOSION2: // color mapped explosion
|
case TE_EXPLOSION2: // color mapped explosion
|
||||||
|
@ -245,7 +298,8 @@ void CL_ParseTEnt (void)
|
||||||
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
pos[2] = MSG_ReadCoord (cl.protocolflags);
|
||||||
colorStart = MSG_ReadByte ();
|
colorStart = MSG_ReadByte ();
|
||||||
colorLength = MSG_ReadByte ();
|
colorLength = MSG_ReadByte ();
|
||||||
R_ParticleExplosion2 (pos, colorStart, colorLength);
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, va("TE_EXPLOSION2_%i_%i", colorStart, colorLength)))
|
||||||
|
R_ParticleExplosion2 (pos, colorStart, colorLength);
|
||||||
dl = CL_AllocDlight (0);
|
dl = CL_AllocDlight (0);
|
||||||
VectorCopy (pos, dl->origin);
|
VectorCopy (pos, dl->origin);
|
||||||
dl->radius = 350;
|
dl->radius = 350;
|
||||||
|
@ -254,11 +308,196 @@ void CL_ParseTEnt (void)
|
||||||
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TENEH_LIGHTNING4:
|
||||||
|
{
|
||||||
|
const char *beamname = MSG_ReadString();
|
||||||
|
CL_ParseBeam (Mod_ForName(beamname, true), "TE_LIGHTNING4", "TE_LIGHTNING4_END");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TEDP_CUSTOMFLASH:
|
||||||
|
dl = CL_AllocDlight (0);
|
||||||
|
dl->origin[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dl->origin[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dl->origin[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dl->radius = 8*MSG_ReadByte();
|
||||||
|
dl->die = (MSG_ReadByte()+1)*(1/256.0);
|
||||||
|
dl->decay = dl->radius / dl->die;
|
||||||
|
dl->die += cl.time;
|
||||||
|
dl->color[0] = MSG_ReadByte()*(1/127.0);
|
||||||
|
dl->color[1] = MSG_ReadByte()*(1/127.0);
|
||||||
|
dl->color[2] = MSG_ReadByte()*(1/127.0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TEDP_PARTICLERAIN:
|
||||||
|
case TEDP_PARTICLESNOW:
|
||||||
|
{
|
||||||
|
vec3_t dir, pos2;
|
||||||
|
int cnt, colour;
|
||||||
|
|
||||||
|
//min
|
||||||
|
pos[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
|
||||||
|
//max
|
||||||
|
pos2[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos2[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos2[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
|
||||||
|
//dir
|
||||||
|
dir[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dir[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dir[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
|
||||||
|
cnt = (unsigned short)MSG_ReadShort(); //count
|
||||||
|
colour = MSG_ReadByte (); //colour
|
||||||
|
|
||||||
|
PScript_RunParticleWeather(pos, pos2, dir, cnt, colour, ((type==TEDP_PARTICLESNOW)?"snow":"rain"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TEDP_BLOOD:
|
||||||
|
{
|
||||||
|
vec3_t dir;
|
||||||
|
int cnt;
|
||||||
|
pos[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dir[0] = MSG_ReadChar();
|
||||||
|
dir[1] = MSG_ReadChar();
|
||||||
|
dir[2] = MSG_ReadChar();
|
||||||
|
cnt = MSG_ReadByte();
|
||||||
|
if (PScript_RunParticleEffectTypeString(pos, dir, cnt, "TE_BLOOD"))
|
||||||
|
Con_Printf ("CL_ParseTEnt: TEDP_BLOOD unavailable\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TEDP_SPARK:
|
||||||
|
{
|
||||||
|
vec3_t dir;
|
||||||
|
int cnt;
|
||||||
|
pos[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dir[0] = MSG_ReadChar();
|
||||||
|
dir[1] = MSG_ReadChar();
|
||||||
|
dir[2] = MSG_ReadChar();
|
||||||
|
cnt = MSG_ReadByte();
|
||||||
|
if (PScript_RunParticleEffectTypeString(pos, dir, cnt, "TE_SPARK"))
|
||||||
|
Con_Printf ("CL_ParseTEnt: TEDP_SPARK unavailable\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TEDP_SMALLFLASH: // [vector] origin
|
||||||
|
pos[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, "TE_SMALLFLASH"))
|
||||||
|
Con_Printf ("CL_ParseTEnt: TEDP_SMALLFLASH unavailable\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
//spike: these are all kinda useless once the ssqc has access to pointparticles...
|
||||||
|
//I'm too lazy to bother implementing them properly.
|
||||||
|
case TEDP_BLOODSHOWER:
|
||||||
|
/*mins[0] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*mins[1] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*mins[2] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*maxs[0] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*maxs[1] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*maxs[2] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*velspeed =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*count =*/ MSG_ReadShort();
|
||||||
|
Con_Printf ("CL_ParseTEnt: TEDP_BLOODSHOWER unsupported\n");
|
||||||
|
break;
|
||||||
|
case TEDP_EXPLOSIONRGB:
|
||||||
|
/*pos[0] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*pos[1] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*pos[2] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*col[0] =*/ MSG_ReadByte();
|
||||||
|
/*col[1] =*/ MSG_ReadByte();
|
||||||
|
/*col[2] =*/ MSG_ReadByte();
|
||||||
|
Con_Printf ("CL_ParseTEnt: TEDP_EXPLOSIONRGB unsupported\n");
|
||||||
|
break;
|
||||||
|
case TEDP_PARTICLECUBE:
|
||||||
|
/*mins[0] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*mins[1] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*mins[2] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*maxs[0] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*maxs[1] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*maxs[2] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*dir[0] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*dir[1] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*dir[2] =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
/*count =*/ MSG_ReadShort();
|
||||||
|
/*pal_start =*/ MSG_ReadByte();
|
||||||
|
/*pal_rand =*/ MSG_ReadByte();
|
||||||
|
/*velspeed =*/ MSG_ReadCoord(cl.protocolflags);
|
||||||
|
Con_Printf ("CL_ParseTEnt: TEDP_PARTICLECUBE unsupported\n");
|
||||||
|
break;
|
||||||
|
case TEDP_FLAMEJET:
|
||||||
|
{
|
||||||
|
vec3_t dir;
|
||||||
|
int cnt;
|
||||||
|
pos[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dir[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dir[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
dir[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
cnt = MSG_ReadByte();
|
||||||
|
if (PScript_RunParticleEffectTypeString(pos, dir, cnt, "TE_FLAMEJET"))
|
||||||
|
Con_Printf ("CL_ParseTEnt: TEDP_FLAMEJET unavailable\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TEDP_PLASMABURN:
|
||||||
|
pos[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
pos[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
if (PScript_RunParticleEffectTypeString(pos, NULL, 1, "TE_PLASMABURN"))
|
||||||
|
Con_Printf ("CL_ParseTEnt: TEDP_PLASMABURN unavailable\n");
|
||||||
|
break;
|
||||||
|
case TEDP_TEI_G3:
|
||||||
|
Host_Error ("CL_ParseTEnt: TEDP_TEI_G3 unsupported");
|
||||||
|
case TEDP_SMOKE:
|
||||||
|
Host_Error ("CL_ParseTEnt: TEDP_SMOKE unsupported");
|
||||||
|
case TEDP_TEI_BIGEXPLOSION:
|
||||||
|
Host_Error ("CL_ParseTEnt: TEDP_TEI_BIGEXPLOSION unsupported");
|
||||||
|
case TEDP_TEI_PLASMAHIT:
|
||||||
|
Host_Error ("CL_ParseTEnt: TEDP_TEI_PLASMAHIT unsupported");
|
||||||
default:
|
default:
|
||||||
Sys_Error ("CL_ParseTEnt: bad type");
|
Host_Error ("CL_ParseTEnt: unsupported tempentity type %i", type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CL_ParseEffect (qboolean big)
|
||||||
|
{
|
||||||
|
vec3_t org;
|
||||||
|
int modelindex;
|
||||||
|
int startframe;
|
||||||
|
int framecount;
|
||||||
|
int framerate;
|
||||||
|
qmodel_t *mod;
|
||||||
|
|
||||||
|
org[0] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
org[1] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
org[2] = MSG_ReadCoord(cl.protocolflags);
|
||||||
|
|
||||||
|
if (big)
|
||||||
|
modelindex = MSG_ReadShort();
|
||||||
|
else
|
||||||
|
modelindex = MSG_ReadByte();
|
||||||
|
|
||||||
|
if (big)
|
||||||
|
startframe = MSG_ReadShort();
|
||||||
|
else
|
||||||
|
startframe = MSG_ReadByte();
|
||||||
|
|
||||||
|
framecount = MSG_ReadByte();
|
||||||
|
framerate = MSG_ReadByte();
|
||||||
|
|
||||||
|
mod = cl.model_precache[modelindex];
|
||||||
|
CL_SpawnSpriteEffect(org/*, NULL, NULL*/, mod, startframe, framecount, framerate/*, mod->type==mod_sprite?-1:1, 1, 0, 0, P_INVALID, 0, 0*/);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
|
@ -269,7 +508,7 @@ entity_t *CL_NewTempEntity (void)
|
||||||
{
|
{
|
||||||
entity_t *ent;
|
entity_t *ent;
|
||||||
|
|
||||||
if (cl_numvisedicts == MAX_VISEDICTS)
|
if (cl_numvisedicts == cl_maxvisedicts)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (num_temp_entities == MAX_TEMP_ENTITIES)
|
if (num_temp_entities == MAX_TEMP_ENTITIES)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -279,6 +518,8 @@ entity_t *CL_NewTempEntity (void)
|
||||||
cl_visedicts[cl_numvisedicts] = ent;
|
cl_visedicts[cl_numvisedicts] = ent;
|
||||||
cl_numvisedicts++;
|
cl_numvisedicts++;
|
||||||
|
|
||||||
|
ent->netstate.scale = 16;
|
||||||
|
ent->netstate.colormod[0] = ent->netstate.colormod[1] = ent->netstate.colormod[2] = 32;
|
||||||
ent->colormap = vid.colormap;
|
ent->colormap = vid.colormap;
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
@ -301,7 +542,8 @@ void CL_UpdateTEnts (void)
|
||||||
|
|
||||||
num_temp_entities = 0;
|
num_temp_entities = 0;
|
||||||
|
|
||||||
srand ((int) (cl.time * 1000)); //johnfitz -- freeze beams when paused
|
if (cl.paused)
|
||||||
|
srand ((int) (cl.time * 1000)); //johnfitz -- freeze beams when paused
|
||||||
|
|
||||||
// update lightning
|
// update lightning
|
||||||
for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
|
for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
|
||||||
|
@ -310,11 +552,14 @@ void CL_UpdateTEnts (void)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// if coming from the player, update the start position
|
// if coming from the player, update the start position
|
||||||
if (b->entity == cl.viewentity)
|
if (b->entity == cl.viewentity && cl.entities)
|
||||||
{
|
{
|
||||||
VectorCopy (cl_entities[cl.viewentity].origin, b->start);
|
VectorCopy (cl.entities[cl.viewentity].origin, b->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!PScript_ParticleTrail(b->start, b->end, PScript_FindParticleType(b->trailname), b->entity, NULL, &b->trailstate))
|
||||||
|
continue;
|
||||||
|
|
||||||
// calculate pitch and yaw
|
// calculate pitch and yaw
|
||||||
VectorSubtract (b->end, b->start, dist);
|
VectorSubtract (b->end, b->start, dist);
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ typedef struct
|
||||||
float entertime;
|
float entertime;
|
||||||
int frags;
|
int frags;
|
||||||
int colors; // two 4 bit fields
|
int colors; // two 4 bit fields
|
||||||
|
int ping;
|
||||||
byte translations[VID_GRADES*256];
|
byte translations[VID_GRADES*256];
|
||||||
} scoreboard_t;
|
} scoreboard_t;
|
||||||
|
|
||||||
|
@ -83,6 +84,8 @@ typedef struct
|
||||||
struct qmodel_s *model;
|
struct qmodel_s *model;
|
||||||
float endtime;
|
float endtime;
|
||||||
vec3_t start, end;
|
vec3_t start, end;
|
||||||
|
const char *trailname;
|
||||||
|
struct trailstate_s *trailstate;
|
||||||
} beam_t;
|
} beam_t;
|
||||||
|
|
||||||
#define MAX_MAPSTRING 2048
|
#define MAX_MAPSTRING 2048
|
||||||
|
@ -131,6 +134,16 @@ typedef struct
|
||||||
struct qsocket_s *netcon;
|
struct qsocket_s *netcon;
|
||||||
sizebuf_t message; // writing buffer to send to server
|
sizebuf_t message; // writing buffer to send to server
|
||||||
|
|
||||||
|
//downloads don't restart/fail when the server sends random serverinfo packets
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
qboolean active;
|
||||||
|
unsigned int size;
|
||||||
|
FILE *file;
|
||||||
|
char current[MAX_QPATH]; //also prevents us from repeatedly trying to download the same file
|
||||||
|
char temp[MAX_OSPATH]; //the temp filename for the download, will be renamed to current
|
||||||
|
float starttime;
|
||||||
|
} download;
|
||||||
} client_static_t;
|
} client_static_t;
|
||||||
|
|
||||||
extern client_static_t cls;
|
extern client_static_t cls;
|
||||||
|
@ -149,6 +162,7 @@ typedef struct
|
||||||
|
|
||||||
// information for local display
|
// information for local display
|
||||||
int stats[MAX_CL_STATS]; // health, etc
|
int stats[MAX_CL_STATS]; // health, etc
|
||||||
|
float statsf[MAX_CL_STATS];
|
||||||
int items; // inventory bit flags
|
int items; // inventory bit flags
|
||||||
float item_gettime[32]; // cl.time of aquiring item, for blinking
|
float item_gettime[32]; // cl.time of aquiring item, for blinking
|
||||||
float faceanimtime; // use anim frame if cl.time < this
|
float faceanimtime; // use anim frame if cl.time < this
|
||||||
|
@ -171,13 +185,11 @@ typedef struct
|
||||||
vec3_t punchangle; // temporary offset
|
vec3_t punchangle; // temporary offset
|
||||||
|
|
||||||
// pitch drifting vars
|
// pitch drifting vars
|
||||||
float idealpitch;
|
|
||||||
float pitchvel;
|
float pitchvel;
|
||||||
qboolean nodrift;
|
qboolean nodrift;
|
||||||
float driftmove;
|
float driftmove;
|
||||||
double laststop;
|
double laststop;
|
||||||
|
|
||||||
float viewheight;
|
|
||||||
float crouch; // local amount for smoothing stepups
|
float crouch; // local amount for smoothing stepups
|
||||||
|
|
||||||
qboolean paused; // send over by server
|
qboolean paused; // send over by server
|
||||||
|
@ -213,10 +225,18 @@ typedef struct
|
||||||
struct qmodel_s *worldmodel; // cl_entitites[0].model
|
struct qmodel_s *worldmodel; // cl_entitites[0].model
|
||||||
struct efrag_s *free_efrags;
|
struct efrag_s *free_efrags;
|
||||||
int num_efrags;
|
int num_efrags;
|
||||||
int num_entities; // held in cl_entities array
|
// int num_entities; // held in cl_entities array
|
||||||
int num_statics; // held in cl_staticentities array
|
// int num_statics; // held in cl_staticentities array
|
||||||
entity_t viewent; // the gun model
|
entity_t viewent; // the gun model
|
||||||
|
|
||||||
|
entity_t *entities; //spike -- moved into here
|
||||||
|
int max_edicts;
|
||||||
|
int num_entities;
|
||||||
|
|
||||||
|
entity_t **static_entities; //spike -- was static
|
||||||
|
int max_static_entities;
|
||||||
|
int num_statics;
|
||||||
|
|
||||||
int cdtrack, looptrack; // cd audio
|
int cdtrack, looptrack; // cd audio
|
||||||
|
|
||||||
// frag scoreboard
|
// frag scoreboard
|
||||||
|
@ -224,6 +244,43 @@ typedef struct
|
||||||
|
|
||||||
unsigned protocol; //johnfitz
|
unsigned protocol; //johnfitz
|
||||||
unsigned protocolflags;
|
unsigned protocolflags;
|
||||||
|
unsigned protocol_pext2; //spike -- flag of fte protocol extensions
|
||||||
|
qboolean protocol_dpdownload;
|
||||||
|
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
qboolean protocol_particles;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
int index;
|
||||||
|
} particle_precache[MAX_PARTICLETYPES];
|
||||||
|
#endif
|
||||||
|
int ackframes[8]; //big enough to cover burst
|
||||||
|
unsigned int ackframes_count;
|
||||||
|
qboolean requestresend;
|
||||||
|
|
||||||
|
char stuffcmdbuf[1024]; //comment-extensions are a thing with certain servers, make sure we can handle them properly without further hacks/breakages. there's also some server->client only console commands that we might as well try to handle a bit better, like reconnect
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PRINT_NONE,
|
||||||
|
PRINT_PINGS,
|
||||||
|
// PRINT_STATUSINFO,
|
||||||
|
// PRINT_STATUSPLAYER,
|
||||||
|
// PRINT_STATUSIP,
|
||||||
|
} printtype;
|
||||||
|
int printplayer;
|
||||||
|
float expectingpingtimes;
|
||||||
|
float printversionresponse;
|
||||||
|
|
||||||
|
//spike -- moved this stuff here to deal with downloading content named by the server
|
||||||
|
qboolean sendprespawn; //download+load content, send the prespawn command once done
|
||||||
|
int model_count;
|
||||||
|
int model_download;
|
||||||
|
char model_name[MAX_MODELS][MAX_QPATH];
|
||||||
|
int sound_count;
|
||||||
|
int sound_download;
|
||||||
|
char sound_name[MAX_SOUNDS][MAX_QPATH];
|
||||||
|
//spike -- end downloads
|
||||||
} client_state_t;
|
} client_state_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -249,6 +306,7 @@ extern cvar_t cl_alwaysrun; // QuakeSpasm
|
||||||
|
|
||||||
extern cvar_t cl_autofire;
|
extern cvar_t cl_autofire;
|
||||||
|
|
||||||
|
extern cvar_t cl_recordingdemo;
|
||||||
extern cvar_t cl_shownet;
|
extern cvar_t cl_shownet;
|
||||||
extern cvar_t cl_nolerp;
|
extern cvar_t cl_nolerp;
|
||||||
|
|
||||||
|
@ -265,23 +323,18 @@ extern cvar_t m_forward;
|
||||||
extern cvar_t m_side;
|
extern cvar_t m_side;
|
||||||
|
|
||||||
|
|
||||||
#define MAX_TEMP_ENTITIES 256 //johnfitz -- was 64
|
#define MAX_TEMP_ENTITIES 256 //johnfitz -- was 64
|
||||||
#define MAX_STATIC_ENTITIES 4096 //ericw -- was 512 //johnfitz -- was 128
|
|
||||||
#define MAX_VISEDICTS 4096 // larger, now we support BSP2
|
|
||||||
|
|
||||||
extern client_state_t cl;
|
extern client_state_t cl;
|
||||||
|
|
||||||
// FIXME, allocate dynamically
|
// FIXME, allocate dynamically
|
||||||
extern entity_t cl_static_entities[MAX_STATIC_ENTITIES];
|
|
||||||
extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
|
extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
|
||||||
extern dlight_t cl_dlights[MAX_DLIGHTS];
|
extern dlight_t cl_dlights[MAX_DLIGHTS];
|
||||||
extern entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
|
extern entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
|
||||||
extern beam_t cl_beams[MAX_BEAMS];
|
extern beam_t cl_beams[MAX_BEAMS];
|
||||||
extern entity_t *cl_visedicts[MAX_VISEDICTS];
|
extern entity_t **cl_visedicts;
|
||||||
extern int cl_numvisedicts;
|
extern int cl_numvisedicts;
|
||||||
|
extern int cl_maxvisedicts; //extended if we exceeded it the previous frame
|
||||||
extern entity_t *cl_entities; //johnfitz -- was a static array, now on hunk
|
|
||||||
extern int cl_max_edicts; //johnfitz -- only changes when new map loads
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
|
@ -322,10 +375,15 @@ void CL_SendMove (const usercmd_t *cmd);
|
||||||
int CL_ReadFromServer (void);
|
int CL_ReadFromServer (void);
|
||||||
void CL_BaseMove (usercmd_t *cmd);
|
void CL_BaseMove (usercmd_t *cmd);
|
||||||
|
|
||||||
|
void CL_Download_Data(void);
|
||||||
|
qboolean CL_CheckDownloads(void);
|
||||||
|
|
||||||
|
void CL_ParseEffect (qboolean big);
|
||||||
void CL_ParseTEnt (void);
|
void CL_ParseTEnt (void);
|
||||||
void CL_UpdateTEnts (void);
|
void CL_UpdateTEnts (void);
|
||||||
|
|
||||||
void CL_ClearState (void);
|
void CL_ClearState (void);
|
||||||
|
void CL_ClearTrailStates(void);
|
||||||
|
|
||||||
//
|
//
|
||||||
// cl_demo.c
|
// cl_demo.c
|
||||||
|
@ -342,7 +400,8 @@ void CL_TimeDemo_f (void);
|
||||||
// cl_parse.c
|
// cl_parse.c
|
||||||
//
|
//
|
||||||
void CL_ParseServerMessage (void);
|
void CL_ParseServerMessage (void);
|
||||||
void CL_NewTranslation (int slot);
|
void CL_RegisterParticles(void);
|
||||||
|
//void CL_NewTranslation (int slot);
|
||||||
|
|
||||||
//
|
//
|
||||||
// view
|
// view
|
||||||
|
@ -361,6 +420,7 @@ void V_SetContentsColor (int contents);
|
||||||
//
|
//
|
||||||
void CL_InitTEnts (void);
|
void CL_InitTEnts (void);
|
||||||
void CL_SignonReply (void);
|
void CL_SignonReply (void);
|
||||||
|
float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int *ent);
|
||||||
|
|
||||||
//
|
//
|
||||||
// chase
|
// chase
|
||||||
|
|
103
Quake/cmd.c
103
Quake/cmd.c
|
@ -24,6 +24,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
|
|
||||||
|
cvar_t cl_nopext = {"cl_nopext","0",CVAR_NONE}; //Spike -- prevent autodetection of protocol extensions, so that servers fall back to only their base protocol (without needing to reconfigure the server. Requires reconnect.
|
||||||
|
cvar_t cmd_warncmd = {"cl_warncmd","1",CVAR_NONE}; //Spike -- prevent autodetection of protocol extensions, so that servers fall back to only their base protocol (without needing to reconfigure the server. Requires reconnect.
|
||||||
void Cmd_ForwardToServer (void);
|
void Cmd_ForwardToServer (void);
|
||||||
|
|
||||||
#define MAX_ALIAS_NAME 32
|
#define MAX_ALIAS_NAME 32
|
||||||
|
@ -97,7 +99,17 @@ void Cbuf_AddText (const char *text)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SZ_Write (&cmd_text, text, Q_strlen (text));
|
SZ_Write (&cmd_text, text, l);
|
||||||
|
}
|
||||||
|
void Cbuf_AddTextLen (const char *text, int l)
|
||||||
|
{
|
||||||
|
if (cmd_text.cursize + l >= cmd_text.maxsize)
|
||||||
|
{
|
||||||
|
Con_Printf ("Cbuf_AddText: overflow\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SZ_Write (&cmd_text, text, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,7 +159,7 @@ void Cbuf_Execute (void)
|
||||||
int i;
|
int i;
|
||||||
char *text;
|
char *text;
|
||||||
char line[1024];
|
char line[1024];
|
||||||
int quotes;
|
int quotes, comment;
|
||||||
|
|
||||||
while (cmd_text.cursize)
|
while (cmd_text.cursize)
|
||||||
{
|
{
|
||||||
|
@ -155,11 +167,14 @@ void Cbuf_Execute (void)
|
||||||
text = (char *)cmd_text.data;
|
text = (char *)cmd_text.data;
|
||||||
|
|
||||||
quotes = 0;
|
quotes = 0;
|
||||||
|
comment = 0;
|
||||||
for (i=0 ; i< cmd_text.cursize ; i++)
|
for (i=0 ; i< cmd_text.cursize ; i++)
|
||||||
{
|
{
|
||||||
if (text[i] == '"')
|
if (text[i] == '"')
|
||||||
quotes++;
|
quotes++;
|
||||||
if ( !(quotes&1) && text[i] == ';')
|
if (text[i] == '/' && text[i+1] == '/')
|
||||||
|
comment=true;
|
||||||
|
if ( !(quotes&1) && !comment && text[i] == ';')
|
||||||
break; // don't break if inside a quoted string
|
break; // don't break if inside a quoted string
|
||||||
if (text[i] == '\n')
|
if (text[i] == '\n')
|
||||||
break;
|
break;
|
||||||
|
@ -270,10 +285,12 @@ void Cmd_Exec_f (void)
|
||||||
f = (char *)COM_LoadHunkFile (Cmd_Argv(1), NULL);
|
f = (char *)COM_LoadHunkFile (Cmd_Argv(1), NULL);
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
|
if (cmd_warncmd.value)
|
||||||
|
Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Con_Printf ("execing %s\n",Cmd_Argv(1));
|
if (cmd_warncmd.value)
|
||||||
|
Con_Printf ("execing %s\n",Cmd_Argv(1));
|
||||||
|
|
||||||
Cbuf_InsertText (f);
|
Cbuf_InsertText (f);
|
||||||
Hunk_FreeToLowMark (mark);
|
Hunk_FreeToLowMark (mark);
|
||||||
|
@ -410,6 +427,17 @@ void Cmd_Unalias_f (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qboolean Cmd_AliasExists (const char *aliasname)
|
||||||
|
{
|
||||||
|
cmdalias_t *a;
|
||||||
|
for (a=cmd_alias ; a ; a=a->next)
|
||||||
|
{
|
||||||
|
if (!q_strcasecmp (aliasname, a->name))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
Cmd_Unaliasall_f -- johnfitz
|
Cmd_Unaliasall_f -- johnfitz
|
||||||
|
@ -436,14 +464,6 @@ void Cmd_Unaliasall_f (void)
|
||||||
=============================================================================
|
=============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct cmd_function_s
|
|
||||||
{
|
|
||||||
struct cmd_function_s *next;
|
|
||||||
const char *name;
|
|
||||||
xcommand_t function;
|
|
||||||
} cmd_function_t;
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_ARGS 80
|
#define MAX_ARGS 80
|
||||||
|
|
||||||
static int cmd_argc;
|
static int cmd_argc;
|
||||||
|
@ -536,7 +556,7 @@ void Cmd_Apropos_f(void)
|
||||||
}
|
}
|
||||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||||
{
|
{
|
||||||
if (q_strcasestr(cmd->name, substr))
|
if (q_strcasestr(cmd->name, substr) && cmd->srctype != src_server)
|
||||||
{
|
{
|
||||||
hits++;
|
hits++;
|
||||||
Con_SafePrintf ("%s\n", Cmd_TintSubstring(cmd->name, substr, tmpbuf, sizeof(tmpbuf)));
|
Con_SafePrintf ("%s\n", Cmd_TintSubstring(cmd->name, substr, tmpbuf, sizeof(tmpbuf)));
|
||||||
|
@ -575,6 +595,9 @@ void Cmd_Init (void)
|
||||||
|
|
||||||
Cmd_AddCommand ("apropos", Cmd_Apropos_f);
|
Cmd_AddCommand ("apropos", Cmd_Apropos_f);
|
||||||
Cmd_AddCommand ("find", Cmd_Apropos_f);
|
Cmd_AddCommand ("find", Cmd_Apropos_f);
|
||||||
|
|
||||||
|
Cvar_RegisterVariable (&cl_nopext);
|
||||||
|
Cvar_RegisterVariable (&cmd_warncmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -664,9 +687,11 @@ void Cmd_TokenizeString (const char *text)
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
Cmd_AddCommand
|
Cmd_AddCommand
|
||||||
|
|
||||||
|
spike -- added an extra arg for client (also renamed and made a macro)
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
void Cmd_AddCommand (const char *cmd_name, xcommand_t function)
|
void Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t srctype)
|
||||||
{
|
{
|
||||||
cmd_function_t *cmd;
|
cmd_function_t *cmd;
|
||||||
cmd_function_t *cursor,*prev; //johnfitz -- sorted list insert
|
cmd_function_t *cursor,*prev; //johnfitz -- sorted list insert
|
||||||
|
@ -684,7 +709,7 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function)
|
||||||
// fail if the command already exists
|
// fail if the command already exists
|
||||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||||
{
|
{
|
||||||
if (!Q_strcmp (cmd_name, cmd->name))
|
if (!Q_strcmp (cmd_name, cmd->name) && cmd->srctype == srctype)
|
||||||
{
|
{
|
||||||
Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
|
Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
|
||||||
return;
|
return;
|
||||||
|
@ -694,6 +719,7 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function)
|
||||||
cmd = (cmd_function_t *) Hunk_Alloc (sizeof(cmd_function_t));
|
cmd = (cmd_function_t *) Hunk_Alloc (sizeof(cmd_function_t));
|
||||||
cmd->name = cmd_name;
|
cmd->name = cmd_name;
|
||||||
cmd->function = function;
|
cmd->function = function;
|
||||||
|
cmd->srctype = srctype;
|
||||||
|
|
||||||
//johnfitz -- insert each entry in alphabetical order
|
//johnfitz -- insert each entry in alphabetical order
|
||||||
if (cmd_functions == NULL || strcmp(cmd->name, cmd_functions->name) < 0) //insert at front
|
if (cmd_functions == NULL || strcmp(cmd->name, cmd_functions->name) < 0) //insert at front
|
||||||
|
@ -767,7 +793,7 @@ A complete command line has been parsed, so try to execute it
|
||||||
FIXME: lookupnoadd the token to speed search?
|
FIXME: lookupnoadd the token to speed search?
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
void Cmd_ExecuteString (const char *text, cmd_source_t src)
|
qboolean Cmd_ExecuteString (const char *text, cmd_source_t src)
|
||||||
{
|
{
|
||||||
cmd_function_t *cmd;
|
cmd_function_t *cmd;
|
||||||
cmdalias_t *a;
|
cmdalias_t *a;
|
||||||
|
@ -777,32 +803,49 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
|
||||||
|
|
||||||
// execute the command line
|
// execute the command line
|
||||||
if (!Cmd_Argc())
|
if (!Cmd_Argc())
|
||||||
return; // no tokens
|
return true; // no tokens
|
||||||
|
|
||||||
// check functions
|
// check functions
|
||||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||||
{
|
{
|
||||||
if (!q_strcasecmp (cmd_argv[0],cmd->name))
|
if (!q_strcasecmp (cmd_argv[0],cmd->name))
|
||||||
{
|
{
|
||||||
cmd->function ();
|
if (src == src_client && cmd->srctype != src_client)
|
||||||
return;
|
Con_DPrintf("%s tried to %s\n", host_client->name, text); //src_client only allows client commands
|
||||||
|
else if (src == src_command && cmd->srctype == src_server)
|
||||||
|
continue; //src_command can execute anything but server commands (which it ignores, allowing for alternative behaviour)
|
||||||
|
else if (src == src_server && cmd->srctype != src_server)
|
||||||
|
continue; //src_server may only execute server commands (such commands must be safe to parse within the context of a network message, so no disconnect/connect/playdemo/etc)
|
||||||
|
else
|
||||||
|
cmd->function ();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (src == src_client)
|
||||||
|
{ //spike -- please don't execute similarly named aliases, nor custom cvars...
|
||||||
|
Con_DPrintf("%s tried to %s\n", host_client->name, text);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (src != src_command)
|
||||||
|
return false;
|
||||||
|
|
||||||
// check alias
|
// check alias
|
||||||
for (a=cmd_alias ; a ; a=a->next)
|
for (a=cmd_alias ; a ; a=a->next)
|
||||||
{
|
{
|
||||||
if (!q_strcasecmp (cmd_argv[0], a->name))
|
if (!q_strcasecmp (cmd_argv[0], a->name))
|
||||||
{
|
{
|
||||||
Cbuf_InsertText (a->value);
|
Cbuf_InsertText (a->value);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check cvars
|
// check cvars
|
||||||
if (!Cvar_Command ())
|
if (!Cvar_Command ())
|
||||||
Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
|
if (cmd_warncmd.value || developer.value)
|
||||||
|
Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -830,6 +873,22 @@ void Cmd_ForwardToServer (void)
|
||||||
SZ_Print (&cls.message, Cmd_Argv(0));
|
SZ_Print (&cls.message, Cmd_Argv(0));
|
||||||
SZ_Print (&cls.message, " ");
|
SZ_Print (&cls.message, " ");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//hack zone for compat.
|
||||||
|
//stuffcmd("cmd foo\n") is a good way to query the client to see if it knows foo because the server is guarenteed a response even if it doesn't understand it, saving a timeout
|
||||||
|
if (!strcmp(Cmd_Args(), "protocols"))
|
||||||
|
{ //server asked us for a list of protocol numbers that we claim to support. this allows cool servers like fte to autodetect higher limits etc.
|
||||||
|
//servers may assume that the client's preferred protocol will be listed first.
|
||||||
|
SZ_Print (&cls.message, va("protocols %i %i %i %i %i", PROTOCOL_RMQ, PROTOCOL_FITZQUAKE, PROTOCOL_VERSION_BJP3, PROTOCOL_VERSION_DP7, PROTOCOL_NETQUAKE));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(Cmd_Args(), "pext") && !cl_nopext.value)
|
||||||
|
{ //server asked us for a key+value list of the extensions+attributes we support
|
||||||
|
SZ_Print (&cls.message, va("pext %#x %#x", PROTOCOL_FTE_PEXT2, PEXT2_SUPPORTED_CLIENT));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (Cmd_Argc() > 1)
|
if (Cmd_Argc() > 1)
|
||||||
SZ_Print (&cls.message, Cmd_Args());
|
SZ_Print (&cls.message, Cmd_Args());
|
||||||
else
|
else
|
||||||
|
|
25
Quake/cmd.h
25
Quake/cmd.h
|
@ -42,6 +42,7 @@ The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute ();
|
||||||
void Cbuf_Init (void);
|
void Cbuf_Init (void);
|
||||||
// allocates an initial text buffer that will grow as needed
|
// allocates an initial text buffer that will grow as needed
|
||||||
|
|
||||||
|
void Cbuf_AddTextLen (const char *text, int l);
|
||||||
void Cbuf_AddText (const char *text);
|
void Cbuf_AddText (const char *text);
|
||||||
// as new commands are generated from the console or keybindings,
|
// as new commands are generated from the console or keybindings,
|
||||||
// the text is added to the end of the command buffer.
|
// the text is added to the end of the command buffer.
|
||||||
|
@ -70,24 +71,36 @@ not apropriate.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef void (*xcommand_t) (void);
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
src_client, // came in over a net connection as a clc_stringcmd
|
src_client, // came in over a net connection as a clc_stringcmd
|
||||||
// host_client will be valid during this state.
|
// host_client will be valid during this state.
|
||||||
src_command // from the command buffer
|
src_command, // from the command buffer
|
||||||
|
src_server // from a svc_stufftext
|
||||||
} cmd_source_t;
|
} cmd_source_t;
|
||||||
|
|
||||||
extern cmd_source_t cmd_source;
|
extern cmd_source_t cmd_source;
|
||||||
|
|
||||||
|
typedef void (*xcommand_t) (void);
|
||||||
|
typedef struct cmd_function_s
|
||||||
|
{
|
||||||
|
struct cmd_function_s *next;
|
||||||
|
const char *name;
|
||||||
|
xcommand_t function;
|
||||||
|
cmd_source_t srctype;
|
||||||
|
} cmd_function_t;
|
||||||
|
|
||||||
void Cmd_Init (void);
|
void Cmd_Init (void);
|
||||||
|
|
||||||
void Cmd_AddCommand (const char *cmd_name, xcommand_t function);
|
void Cmd_AddCommand2 (const char *cmd_name, xcommand_t function, cmd_source_t srctype);
|
||||||
// called by the init functions of other parts of the program to
|
// called by the init functions of other parts of the program to
|
||||||
// register commands and functions to call for them.
|
// register commands and functions to call for them.
|
||||||
// The cmd_name is referenced later, so it should not be in temp memory
|
// The cmd_name is referenced later, so it should not be in temp memory
|
||||||
|
#define Cmd_AddCommand(cmdname,func) Cmd_AddCommand2(cmdname,func,src_command) //regular console commands
|
||||||
|
#define Cmd_AddCommand_ClientCommand(cmdname,func) Cmd_AddCommand2(cmdname,func,src_client) //command is meant to be safe for anyone to execute.
|
||||||
|
#define Cmd_AddCommand_ServerCommand(cmdname,func) Cmd_AddCommand2(cmdname,func,src_server) //command came from a server
|
||||||
|
#define Cmd_AddCommand_Console Cmd_AddCommand //to make the disabiguation more obvious
|
||||||
|
|
||||||
|
qboolean Cmd_AliasExists (const char *aliasname);
|
||||||
qboolean Cmd_Exists (const char *cmd_name);
|
qboolean Cmd_Exists (const char *cmd_name);
|
||||||
// used by the cvar code to check for cvar / command name overlap
|
// used by the cvar code to check for cvar / command name overlap
|
||||||
|
|
||||||
|
@ -110,7 +123,7 @@ void Cmd_TokenizeString (const char *text);
|
||||||
// Takes a null terminated string. Does not need to be /n terminated.
|
// Takes a null terminated string. Does not need to be /n terminated.
|
||||||
// breaks the string up into arg tokens.
|
// breaks the string up into arg tokens.
|
||||||
|
|
||||||
void Cmd_ExecuteString (const char *text, cmd_source_t src);
|
qboolean Cmd_ExecuteString (const char *text, cmd_source_t src);
|
||||||
// Parses a single line of text into arguments and tries to execute it.
|
// Parses a single line of text into arguments and tries to execute it.
|
||||||
// The text can come from the command buffer, a remote client, or stdin.
|
// The text can come from the command buffer, a remote client, or stdin.
|
||||||
|
|
||||||
|
|
687
Quake/common.c
687
Quake/common.c
|
@ -26,6 +26,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "q_ctype.h"
|
#include "q_ctype.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <dirent.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static char *largv[MAX_NUM_ARGVS + 1];
|
static char *largv[MAX_NUM_ARGVS + 1];
|
||||||
static char argvdummy[] = " ";
|
static char argvdummy[] = " ";
|
||||||
|
|
||||||
|
@ -33,6 +37,7 @@ int safemode;
|
||||||
|
|
||||||
cvar_t registered = {"registered","1",CVAR_ROM}; /* set to correct value in COM_CheckRegistered() */
|
cvar_t registered = {"registered","1",CVAR_ROM}; /* set to correct value in COM_CheckRegistered() */
|
||||||
cvar_t cmdline = {"cmdline","",CVAR_ROM/*|CVAR_SERVERINFO*/}; /* sending cmdline upon CCREQ_RULE_INFO is evil */
|
cvar_t cmdline = {"cmdline","",CVAR_ROM/*|CVAR_SERVERINFO*/}; /* sending cmdline upon CCREQ_RULE_INFO is evil */
|
||||||
|
cvar_t allow_download = {"allow_download", "1"}; /*set to 0 to block file downloads, both client+server*/
|
||||||
|
|
||||||
static qboolean com_modified; // set true if using non-id files
|
static qboolean com_modified; // set true if using non-id files
|
||||||
|
|
||||||
|
@ -923,6 +928,23 @@ float MSG_ReadAngle16 (unsigned int flags)
|
||||||
}
|
}
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
|
||||||
|
//spike -- for downloads
|
||||||
|
byte *MSG_ReadData (unsigned int length)
|
||||||
|
{
|
||||||
|
byte *data;
|
||||||
|
|
||||||
|
if (msg_readcount+length > (unsigned int)net_message.cursize)
|
||||||
|
{
|
||||||
|
msg_badread = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = net_message.data+msg_readcount;
|
||||||
|
msg_readcount += length;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void SZ_Alloc (sizebuf_t *buf, int startsize)
|
void SZ_Alloc (sizebuf_t *buf, int startsize)
|
||||||
|
@ -946,6 +968,7 @@ void SZ_Free (sizebuf_t *buf)
|
||||||
void SZ_Clear (sizebuf_t *buf)
|
void SZ_Clear (sizebuf_t *buf)
|
||||||
{
|
{
|
||||||
buf->cursize = 0;
|
buf->cursize = 0;
|
||||||
|
buf->overflowed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *SZ_GetSpace (sizebuf_t *buf, int length)
|
void *SZ_GetSpace (sizebuf_t *buf, int length)
|
||||||
|
@ -960,9 +983,9 @@ void *SZ_GetSpace (sizebuf_t *buf, int length)
|
||||||
if (length > buf->maxsize)
|
if (length > buf->maxsize)
|
||||||
Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
|
Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
|
||||||
|
|
||||||
buf->overflowed = true;
|
Con_Printf ("SZ_GetSpace: overflow\n");
|
||||||
Con_Printf ("SZ_GetSpace: overflow");
|
|
||||||
SZ_Clear (buf);
|
SZ_Clear (buf);
|
||||||
|
buf->overflowed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = buf->data + buf->cursize;
|
data = buf->data + buf->cursize;
|
||||||
|
@ -1152,6 +1175,56 @@ void COM_AddExtension (char *path, const char *extension, size_t len)
|
||||||
q_strlcat(path, extension, len);
|
q_strlcat(path, extension, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
spike -- this function simply says whether a filename is acceptable for downloading (used by both client+server)
|
||||||
|
*/
|
||||||
|
qboolean COM_DownloadNameOkay(const char *filename)
|
||||||
|
{
|
||||||
|
if (!allow_download.value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//quickly test the prefix to ensure that its in one of the allowed subdirs
|
||||||
|
if (strncmp(filename, "sound/", 6) &&
|
||||||
|
strncmp(filename, "progs/", 6) &&
|
||||||
|
strncmp(filename, "maps/", 5) &&
|
||||||
|
strncmp(filename, "models/", 7))
|
||||||
|
return false;
|
||||||
|
//windows paths are NOT permitted, nor are alternative data streams, nor wildcards, and double quotes are always bad(which allows for spaces)
|
||||||
|
if (strchr(filename, '\\') || strchr(filename, ':') || strchr(filename, '*') || strchr(filename, '?') || strchr(filename, '\"'))
|
||||||
|
return false;
|
||||||
|
//some operating systems interpret this as 'parent directory'
|
||||||
|
if (strstr(filename, "//"))
|
||||||
|
return false;
|
||||||
|
//block unix hidden files, also blocks relative paths.
|
||||||
|
if (*filename == '.' || strstr(filename, "/."))
|
||||||
|
return false;
|
||||||
|
//test the extension to ensure that its in one of the allowed file types
|
||||||
|
//(no .dll, .so, .com, .exe, .bat, .vbs, .xls, .doc, etc please)
|
||||||
|
//also don't allow config files.
|
||||||
|
filename = COM_FileGetExtension(filename);
|
||||||
|
if (
|
||||||
|
//model formats
|
||||||
|
q_strcasecmp(filename, "bsp") &&
|
||||||
|
q_strcasecmp(filename, "mdl") &&
|
||||||
|
q_strcasecmp(filename, "iqm") && //in case we ever support these later
|
||||||
|
q_strcasecmp(filename, "md3") && //in case we ever support these later
|
||||||
|
q_strcasecmp(filename, "spr") &&
|
||||||
|
q_strcasecmp(filename, "spr32") &&
|
||||||
|
//audio formats
|
||||||
|
q_strcasecmp(filename, "wav") &&
|
||||||
|
q_strcasecmp(filename, "ogg") &&
|
||||||
|
//image formats (if we ever need that)
|
||||||
|
q_strcasecmp(filename, "tga") &&
|
||||||
|
q_strcasecmp(filename, "png") &&
|
||||||
|
//misc stuff
|
||||||
|
q_strcasecmp(filename, "lux") &&
|
||||||
|
q_strcasecmp(filename, "lit2") &&
|
||||||
|
q_strcasecmp(filename, "lit"))
|
||||||
|
return false;
|
||||||
|
//okay, well, we didn't throw a hissy fit, so whatever dude, go ahead and download
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============
|
==============
|
||||||
|
@ -1251,11 +1324,11 @@ Returns the position (1 to argc-1) in the program's argument list
|
||||||
where the given parameter apears, or 0 if not present
|
where the given parameter apears, or 0 if not present
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
int COM_CheckParm (const char *parm)
|
int COM_CheckParmNext (int last, const char *parm)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 1; i < com_argc; i++)
|
for (i = last+1; i < com_argc; i++)
|
||||||
{
|
{
|
||||||
if (!com_argv[i])
|
if (!com_argv[i])
|
||||||
continue; // NEXTSTEP sometimes clears appkit vars.
|
continue; // NEXTSTEP sometimes clears appkit vars.
|
||||||
|
@ -1265,6 +1338,10 @@ int COM_CheckParm (const char *parm)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int COM_CheckParm (const char *parm)
|
||||||
|
{
|
||||||
|
return COM_CheckParmNext(0, parm);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
|
@ -1384,6 +1461,23 @@ static void FitzTest_f (void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
entity_state_t nullentitystate;
|
||||||
|
static void COM_SetupNullState(void)
|
||||||
|
{
|
||||||
|
//the null state has some specific default values
|
||||||
|
// nullentitystate.drawflags = /*SCALE_ORIGIN_ORIGIN*/96;
|
||||||
|
nullentitystate.colormod[0] = 32;
|
||||||
|
nullentitystate.colormod[1] = 32;
|
||||||
|
nullentitystate.colormod[2] = 32;
|
||||||
|
// nullentitystate.glowmod[0] = 32;
|
||||||
|
// nullentitystate.glowmod[1] = 32;
|
||||||
|
// nullentitystate.glowmod[2] = 32;
|
||||||
|
nullentitystate.alpha = 0; //fte has 255 by default, with 0 for invisible. fitz uses 1 for invisible, 0 default, and 255=full alpha
|
||||||
|
nullentitystate.scale = 16;
|
||||||
|
// nullentitystate.solidsize = 0;//ES_SOLID_BSP;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
COM_Init
|
COM_Init
|
||||||
|
@ -1435,6 +1529,8 @@ void COM_Init (void)
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Cmd_AddCommand ("fitztest", FitzTest_f); //johnfitz
|
Cmd_AddCommand ("fitztest", FitzTest_f); //johnfitz
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
COM_SetupNullState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1501,6 +1597,7 @@ typedef struct
|
||||||
|
|
||||||
#define MAX_FILES_IN_PACK 2048
|
#define MAX_FILES_IN_PACK 2048
|
||||||
|
|
||||||
|
char com_gamenames[1024]; //eg: "hipnotic;quoth;warp", no id1, no private stuff
|
||||||
char com_gamedir[MAX_OSPATH];
|
char com_gamedir[MAX_OSPATH];
|
||||||
char com_basedir[MAX_OSPATH];
|
char com_basedir[MAX_OSPATH];
|
||||||
int file_from_pak; // ZOID: global indicating that file came from a pak
|
int file_from_pak; // ZOID: global indicating that file came from a pak
|
||||||
|
@ -1636,15 +1733,38 @@ static int COM_FindFile (const char *filename, int *handle, FILE **file,
|
||||||
*path_id = search->path_id;
|
*path_id = search->path_id;
|
||||||
if (handle)
|
if (handle)
|
||||||
{
|
{
|
||||||
*handle = pak->handle;
|
if (pak->files[i].deflatedsize)
|
||||||
Sys_FileSeek (pak->handle, pak->files[i].filepos);
|
{
|
||||||
|
FILE *f;
|
||||||
|
f = fopen (pak->filename, "rb");
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fseek (f, pak->files[i].filepos, SEEK_SET);
|
||||||
|
f = FSZIP_Deflate(f, pak->files[i].deflatedsize, pak->files[i].filelen);
|
||||||
|
*handle = Sys_FileOpenStdio(f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //error!
|
||||||
|
com_filesize = -1;
|
||||||
|
*handle = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*handle = pak->handle;
|
||||||
|
Sys_FileSeek (pak->handle, pak->files[i].filepos);
|
||||||
|
}
|
||||||
return com_filesize;
|
return com_filesize;
|
||||||
}
|
}
|
||||||
else if (file)
|
else if (file)
|
||||||
{ /* open a new file on the pakfile */
|
{ /* open a new file on the pakfile */
|
||||||
*file = fopen (pak->filename, "rb");
|
*file = fopen (pak->filename, "rb");
|
||||||
if (*file)
|
if (*file)
|
||||||
|
{
|
||||||
fseek (*file, pak->files[i].filepos, SEEK_SET);
|
fseek (*file, pak->files[i].filepos, SEEK_SET);
|
||||||
|
if (pak->files[i].deflatedsize)
|
||||||
|
*file = FSZIP_Deflate(*file, pak->files[i].deflatedsize, pak->files[i].filelen);
|
||||||
|
}
|
||||||
return com_filesize;
|
return com_filesize;
|
||||||
}
|
}
|
||||||
else /* for COM_FileExists() */
|
else /* for COM_FileExists() */
|
||||||
|
@ -1659,6 +1779,8 @@ static int COM_FindFile (const char *filename, int *handle, FILE **file,
|
||||||
{ /* if not a registered version, don't ever go beyond base */
|
{ /* if not a registered version, don't ever go beyond base */
|
||||||
if ( strchr (filename, '/') || strchr (filename,'\\'))
|
if ( strchr (filename, '/') || strchr (filename,'\\'))
|
||||||
continue;
|
continue;
|
||||||
|
if (q_strcasecmp(COM_FileGetExtension(filename), "dat")) //don't load custom progs.dats either
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
q_snprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
|
q_snprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
|
||||||
|
@ -1981,20 +2103,22 @@ static pack_t *COM_LoadPackFile (const char *packfile)
|
||||||
if (numpackfiles > MAX_FILES_IN_PACK)
|
if (numpackfiles > MAX_FILES_IN_PACK)
|
||||||
Sys_Error ("%s has %i files", packfile, numpackfiles);
|
Sys_Error ("%s has %i files", packfile, numpackfiles);
|
||||||
|
|
||||||
if (numpackfiles != PAK0_COUNT)
|
|
||||||
com_modified = true; // not the original file
|
|
||||||
|
|
||||||
newfiles = (packfile_t *) Z_Malloc(numpackfiles * sizeof(packfile_t));
|
newfiles = (packfile_t *) Z_Malloc(numpackfiles * sizeof(packfile_t));
|
||||||
|
|
||||||
Sys_FileSeek (packhandle, header.dirofs);
|
Sys_FileSeek (packhandle, header.dirofs);
|
||||||
Sys_FileRead (packhandle, (void *)info, header.dirlen);
|
Sys_FileRead (packhandle, (void *)info, header.dirlen);
|
||||||
|
|
||||||
// crc the directory to check for modifications
|
if (numpackfiles != PAK0_COUNT)
|
||||||
CRC_Init (&crc);
|
com_modified = true; // not the original file
|
||||||
for (i = 0; i < header.dirlen; i++)
|
else
|
||||||
CRC_ProcessByte (&crc, ((byte *)info)[i]);
|
{
|
||||||
if (crc != PAK0_CRC_V106 && crc != PAK0_CRC_V101 && crc != PAK0_CRC_V100)
|
// crc the directory to check for modifications
|
||||||
com_modified = true;
|
CRC_Init (&crc);
|
||||||
|
for (i = 0; i < header.dirlen; i++)
|
||||||
|
CRC_ProcessByte (&crc, ((byte *)info)[i]);
|
||||||
|
if (crc != PAK0_CRC_V106 && crc != PAK0_CRC_V101 && crc != PAK0_CRC_V100)
|
||||||
|
com_modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
// parse the directory
|
// parse the directory
|
||||||
for (i = 0; i < numpackfiles; i++)
|
for (i = 0; i < numpackfiles; i++)
|
||||||
|
@ -2014,19 +2138,172 @@ static pack_t *COM_LoadPackFile (const char *packfile)
|
||||||
return pack;
|
return pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void COM_ListSystemFiles(void *ctx, const char *gamedir, const char *ext, qboolean (*cb)(void *ctx, const char *fname))
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
WIN32_FIND_DATA fdat;
|
||||||
|
HANDLE fhnd;
|
||||||
|
char filestring[MAX_OSPATH];
|
||||||
|
q_snprintf (filestring, sizeof(filestring), "%s/*.%s", gamedir, ext);
|
||||||
|
fhnd = FindFirstFile(filestring, &fdat);
|
||||||
|
if (fhnd == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
cb (ctx, fdat.cFileName);
|
||||||
|
} while (FindNextFile(fhnd, &fdat));
|
||||||
|
FindClose(fhnd);
|
||||||
|
#else
|
||||||
|
DIR *dir_p;
|
||||||
|
struct dirent *dir_t;
|
||||||
|
dir_p = opendir(gamedir);
|
||||||
|
if (dir_p == NULL)
|
||||||
|
return;
|
||||||
|
while ((dir_t = readdir(dir_p)) != NULL)
|
||||||
|
{
|
||||||
|
if (q_strcasecmp(COM_FileGetExtension(dir_t->d_name), ext) != 0)
|
||||||
|
continue;
|
||||||
|
cb (ctx, dir_t->d_name);
|
||||||
|
}
|
||||||
|
closedir(dir_p);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static qboolean COM_AddPackage(searchpath_t *basepath, const char *pakfile)
|
||||||
|
{
|
||||||
|
searchpath_t *search;
|
||||||
|
pack_t *pak;
|
||||||
|
const char *ext = COM_FileGetExtension(pakfile);
|
||||||
|
|
||||||
|
//don't add the same pak twice.
|
||||||
|
for (search = com_searchpaths; search; search = search->next)
|
||||||
|
{
|
||||||
|
if (search->pack)
|
||||||
|
if (!q_strcasecmp(pakfile, search->pack->filename))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!q_strcasecmp(ext, "pak"))
|
||||||
|
pak = COM_LoadPackFile (pakfile);
|
||||||
|
else if (!q_strcasecmp(ext, "pk3") || !q_strcasecmp(ext, "pk4") || !q_strcasecmp(ext, "zip") || !q_strcasecmp(ext, "apk"))
|
||||||
|
{
|
||||||
|
pak = FSZIP_LoadArchive(pakfile);
|
||||||
|
if (pak)
|
||||||
|
com_modified = true; //would always be true, so we don't bother with crcs.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pak = NULL;
|
||||||
|
|
||||||
|
if (!pak)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t));
|
||||||
|
search->path_id = basepath->path_id;
|
||||||
|
search->pack = pak;
|
||||||
|
search->next = com_searchpaths;
|
||||||
|
com_searchpaths = search;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean COM_AddEnumeratedPackage(void *ctx, const char *pakfile)
|
||||||
|
{
|
||||||
|
searchpath_t *basepath = ctx;
|
||||||
|
char fullpakfile[MAX_OSPATH];
|
||||||
|
q_snprintf (fullpakfile, sizeof(fullpakfile), "%s/%s", basepath->filename, pakfile);
|
||||||
|
return COM_AddPackage(basepath, fullpakfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *COM_GetGameNames(qboolean full)
|
||||||
|
{
|
||||||
|
if (full)
|
||||||
|
{
|
||||||
|
if (*com_gamenames)
|
||||||
|
return va("%s;%s", GAMENAME, com_gamenames);
|
||||||
|
else
|
||||||
|
return GAMENAME;
|
||||||
|
}
|
||||||
|
return com_gamenames;
|
||||||
|
// return COM_SkipPath(com_gamedir);
|
||||||
|
}
|
||||||
|
//if either contain id1 then that gets ignored
|
||||||
|
qboolean COM_GameDirMatches(const char *tdirs)
|
||||||
|
{
|
||||||
|
int gnl = strlen(GAMENAME);
|
||||||
|
const char *odirs = COM_GetGameNames(false);
|
||||||
|
|
||||||
|
//ignore any core paths.
|
||||||
|
if (!strncmp(tdirs, GAMENAME, gnl) && (tdirs[gnl] == ';' || !tdirs[gnl]))
|
||||||
|
{
|
||||||
|
tdirs+=gnl;
|
||||||
|
if (*tdirs == ';')
|
||||||
|
tdirs++;
|
||||||
|
}
|
||||||
|
if (!strncmp(odirs, GAMENAME, gnl) && (odirs[gnl] == ';' || !odirs[gnl]))
|
||||||
|
{
|
||||||
|
odirs+=gnl;
|
||||||
|
if (*odirs == ';')
|
||||||
|
odirs++;
|
||||||
|
}
|
||||||
|
//skip any qw in there from quakeworld (remote servers should really be skipping this, unless its maybe the only one in the path).
|
||||||
|
if (!strncmp(tdirs, "qw;", 3) || !strcmp(tdirs, "qw"))
|
||||||
|
{
|
||||||
|
tdirs+=2;
|
||||||
|
if (*tdirs==';')
|
||||||
|
tdirs++;
|
||||||
|
}
|
||||||
|
if (!strncmp(odirs, "qw;", 3) || !strcmp(odirs, "qw")) //need to cope with ourselves setting it that way too, just in case.
|
||||||
|
{
|
||||||
|
odirs+=2;
|
||||||
|
if (*odirs==';')
|
||||||
|
odirs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//okay, now check it properly
|
||||||
|
if (!strcmp(odirs, tdirs))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
COM_AddGameDirectory -- johnfitz -- modified based on topaz's tutorial
|
COM_AddGameDirectory -- johnfitz -- modified based on topaz's tutorial
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static void COM_AddGameDirectory (const char *base, const char *dir)
|
static void COM_AddGameDirectory (const char *dir)
|
||||||
{
|
{
|
||||||
|
const char *base = com_basedir;
|
||||||
int i;
|
int i;
|
||||||
unsigned int path_id;
|
unsigned int path_id;
|
||||||
searchpath_t *search;
|
searchpath_t *searchdir;
|
||||||
pack_t *pak, *qspak;
|
|
||||||
char pakfile[MAX_OSPATH];
|
char pakfile[MAX_OSPATH];
|
||||||
qboolean been_here = false;
|
qboolean been_here = false;
|
||||||
|
FILE *listing;
|
||||||
|
qboolean found;
|
||||||
|
const char *enginepackname = "quakespasm";
|
||||||
|
|
||||||
|
if (*dir == '*')
|
||||||
|
dir++;
|
||||||
|
else if (!strchr(dir, '/') && !strchr(dir, '\\'))
|
||||||
|
{
|
||||||
|
//fixme: block dupes
|
||||||
|
if (*com_gamenames)
|
||||||
|
q_strlcat(com_gamenames, ";", sizeof(com_gamenames));
|
||||||
|
q_strlcat(com_gamenames, dir, sizeof(com_gamenames));
|
||||||
|
}
|
||||||
|
|
||||||
|
//quakespasm enables mission pack flags automatically, so -game rogue works without breaking the hud
|
||||||
|
//we might as well do that here to simplify the code.
|
||||||
|
if (!q_strcasecmp(dir,"rogue")) {
|
||||||
|
rogue = true;
|
||||||
|
standard_quake = false;
|
||||||
|
}
|
||||||
|
if (!q_strcasecmp(dir,"hipnotic") || !q_strcasecmp(dir,"quoth")) {
|
||||||
|
hipnotic = true;
|
||||||
|
standard_quake = false;
|
||||||
|
}
|
||||||
|
|
||||||
q_strlcpy (com_gamedir, va("%s/%s", base, dir), sizeof(com_gamedir));
|
q_strlcpy (com_gamedir, va("%s/%s", base, dir), sizeof(com_gamedir));
|
||||||
|
|
||||||
|
@ -2036,44 +2313,85 @@ static void COM_AddGameDirectory (const char *base, const char *dir)
|
||||||
else path_id = 1U;
|
else path_id = 1U;
|
||||||
|
|
||||||
_add_path:
|
_add_path:
|
||||||
// add the directory to the search path
|
searchdir = (searchpath_t *) Z_Malloc(sizeof(searchpath_t));
|
||||||
search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t));
|
searchdir->path_id = path_id;
|
||||||
search->path_id = path_id;
|
q_strlcpy (searchdir->filename, com_gamedir, sizeof(searchdir->filename));
|
||||||
q_strlcpy (search->filename, com_gamedir, sizeof(search->filename));
|
|
||||||
search->next = com_searchpaths;
|
q_snprintf (pakfile, sizeof(pakfile), "%s/pak.lst", com_gamedir);
|
||||||
com_searchpaths = search;
|
listing = fopen(pakfile, "rb");
|
||||||
|
if (listing)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char *buffer;
|
||||||
|
const char *name;
|
||||||
|
fseek(listing, 0, SEEK_END);
|
||||||
|
len = ftell(listing);
|
||||||
|
fseek(listing, 0, SEEK_SET);
|
||||||
|
buffer = Z_Malloc(len+1);
|
||||||
|
fread(buffer, 1, len, listing);
|
||||||
|
buffer[len] = 0;
|
||||||
|
fclose(listing);
|
||||||
|
|
||||||
|
name = buffer;
|
||||||
|
com_modified = true; //any reordering of paks should be frowned upon
|
||||||
|
while ((name = COM_Parse(name)))
|
||||||
|
{
|
||||||
|
if (!*com_token)
|
||||||
|
continue;
|
||||||
|
if (strchr(com_token, '/') || strchr(com_token, '\\') || strchr(com_token, ':'))
|
||||||
|
continue;
|
||||||
|
q_snprintf (pakfile, sizeof(pakfile), "%s/%s", com_gamedir, com_token);
|
||||||
|
COM_AddPackage(searchdir, pakfile);
|
||||||
|
|
||||||
|
if (path_id == 1 && !fitzmode && !q_strncasecmp(com_token, "pak0.", 5))
|
||||||
|
{ //add this now, to try to retain correct ordering.
|
||||||
|
qboolean old = com_modified;
|
||||||
|
if (been_here) base = host_parms->userdir;
|
||||||
|
q_snprintf (pakfile, sizeof(pakfile), "%s/%s.%s", base, enginepackname, COM_FileGetExtension(com_token));
|
||||||
|
COM_AddPackage(searchdir, pakfile);
|
||||||
|
com_modified = old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add any pak files in the format pak0.pak pak1.pak, ...
|
// add any pak files in the format pak0.pak pak1.pak, ...
|
||||||
for (i = 0; ; i++)
|
for (i = 0; ; i++)
|
||||||
{
|
{
|
||||||
|
found = false;
|
||||||
|
|
||||||
q_snprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", com_gamedir, i);
|
q_snprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", com_gamedir, i);
|
||||||
pak = COM_LoadPackFile (pakfile);
|
found |= COM_AddPackage(searchdir, pakfile);
|
||||||
if (i != 0 || path_id != 1 || fitzmode)
|
q_snprintf (pakfile, sizeof(pakfile), "%s/pak%i.pk3", com_gamedir, i);
|
||||||
qspak = NULL;
|
found |= COM_AddPackage(searchdir, pakfile);
|
||||||
else {
|
|
||||||
|
if (i == 0 && path_id == 1 && !fitzmode)
|
||||||
|
{
|
||||||
qboolean old = com_modified;
|
qboolean old = com_modified;
|
||||||
if (been_here) base = host_parms->userdir;
|
if (been_here) base = host_parms->userdir;
|
||||||
q_snprintf (pakfile, sizeof(pakfile), "%s/quakespasm.pak", base);
|
|
||||||
qspak = COM_LoadPackFile (pakfile);
|
q_snprintf (pakfile, sizeof(pakfile), "%s/%s.pak", base, enginepackname);
|
||||||
|
COM_AddPackage(searchdir, pakfile);
|
||||||
|
q_snprintf (pakfile, sizeof(pakfile), "%s/%s.pk3", base, enginepackname);
|
||||||
|
COM_AddPackage(searchdir, pakfile);
|
||||||
|
|
||||||
com_modified = old;
|
com_modified = old;
|
||||||
}
|
}
|
||||||
if (pak) {
|
if (!found)
|
||||||
search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t));
|
break;
|
||||||
search->path_id = path_id;
|
|
||||||
search->pack = pak;
|
|
||||||
search->next = com_searchpaths;
|
|
||||||
com_searchpaths = search;
|
|
||||||
}
|
|
||||||
if (qspak) {
|
|
||||||
search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t));
|
|
||||||
search->path_id = path_id;
|
|
||||||
search->pack = qspak;
|
|
||||||
search->next = com_searchpaths;
|
|
||||||
com_searchpaths = search;
|
|
||||||
}
|
|
||||||
if (!pak) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i = COM_CheckParm ("-nowildpaks");
|
||||||
|
if (!i)
|
||||||
|
{
|
||||||
|
COM_ListSystemFiles(searchdir, com_gamedir, "pak", COM_AddEnumeratedPackage);
|
||||||
|
COM_ListSystemFiles(searchdir, com_gamedir, "pk3", COM_AddEnumeratedPackage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then finally link the directory to the search path
|
||||||
|
//spike -- moved this last (also explicitly blocked loading progs.dat from system paths when running the demo)
|
||||||
|
searchdir->next = com_searchpaths;
|
||||||
|
com_searchpaths = searchdir;
|
||||||
|
|
||||||
if (!been_here && host_parms->userdir != host_parms->basedir)
|
if (!been_here && host_parms->userdir != host_parms->basedir)
|
||||||
{
|
{
|
||||||
been_here = true;
|
been_here = true;
|
||||||
|
@ -2083,6 +2401,51 @@ _add_path:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void COM_ResetGameDirectories(char *newgamedirs)
|
||||||
|
{
|
||||||
|
char *newpath, *path;
|
||||||
|
searchpath_t *search;
|
||||||
|
//Kill the extra game if it is loaded
|
||||||
|
while (com_searchpaths != com_base_searchpaths)
|
||||||
|
{
|
||||||
|
if (com_searchpaths->pack)
|
||||||
|
{
|
||||||
|
Sys_FileClose (com_searchpaths->pack->handle);
|
||||||
|
Z_Free (com_searchpaths->pack->files);
|
||||||
|
Z_Free (com_searchpaths->pack);
|
||||||
|
}
|
||||||
|
search = com_searchpaths->next;
|
||||||
|
Z_Free (com_searchpaths);
|
||||||
|
com_searchpaths = search;
|
||||||
|
}
|
||||||
|
hipnotic = false;
|
||||||
|
rogue = false;
|
||||||
|
standard_quake = true;
|
||||||
|
//wipe the list of mod gamedirs
|
||||||
|
*com_gamenames = 0;
|
||||||
|
//reset this too
|
||||||
|
q_strlcpy (com_gamedir, va("%s/%s", (host_parms->userdir != host_parms->basedir)?host_parms->userdir:com_basedir, GAMENAME), sizeof(com_gamedir));
|
||||||
|
|
||||||
|
for(newpath = newgamedirs; newpath && *newpath; )
|
||||||
|
{
|
||||||
|
char *e = strchr(newpath, ';');
|
||||||
|
if (e)
|
||||||
|
*e++ = 0;
|
||||||
|
|
||||||
|
if (!q_strcasecmp(GAMENAME, newpath))
|
||||||
|
path = NULL;
|
||||||
|
else for (path = newgamedirs; path < newpath; path += strlen(path)+1)
|
||||||
|
{
|
||||||
|
if (!q_strcasecmp(path, newpath))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path == newpath) //not already loaded
|
||||||
|
COM_AddGameDirectory(newpath);
|
||||||
|
newpath = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
//johnfitz -- dynamic gamedir stuff -- modified by QuakeSpasm team.
|
//johnfitz -- dynamic gamedir stuff -- modified by QuakeSpasm team.
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
@ -2091,9 +2454,8 @@ static void COM_Game_f (void)
|
||||||
{
|
{
|
||||||
if (Cmd_Argc() > 1)
|
if (Cmd_Argc() > 1)
|
||||||
{
|
{
|
||||||
const char *p = Cmd_Argv(1);
|
int i, pri;
|
||||||
const char *p2 = Cmd_Argv(2);
|
char paths[1024];
|
||||||
searchpath_t *search;
|
|
||||||
|
|
||||||
if (!registered.value) //disable shareware quake
|
if (!registered.value) //disable shareware quake
|
||||||
{
|
{
|
||||||
|
@ -2101,44 +2463,45 @@ static void COM_Game_f (void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*p || !strcmp(p, ".") || strstr(p, "..") || strstr(p, "/") || strstr(p, "\\") || strstr(p, ":"))
|
*paths = 0;
|
||||||
|
q_strlcat(paths, GAMENAME, sizeof(paths));
|
||||||
|
for (pri = 0; pri <= 1; pri++)
|
||||||
{
|
{
|
||||||
Con_Printf ("gamedir should be a single directory name, not a path\n");
|
for (i = 1; i < Cmd_Argc(); i++)
|
||||||
return;
|
{
|
||||||
}
|
const char *p = Cmd_Argv(i);
|
||||||
|
if (!*p)
|
||||||
if (*p2)
|
p = GAMENAME;
|
||||||
{
|
if (pri == 0)
|
||||||
if (strcmp(p2,"-hipnotic") && strcmp(p2,"-rogue") && strcmp(p2,"-quoth")) {
|
{
|
||||||
Con_Printf ("invalid mission pack argument to \"game\"\n");
|
if (*p != '-')
|
||||||
return;
|
continue;
|
||||||
}
|
p++;
|
||||||
if (!q_strcasecmp(p, GAMENAME)) {
|
|
||||||
Con_Printf ("no mission pack arguments to %s game\n", GAMENAME);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!q_strcasecmp(p, COM_SkipPath(com_gamedir))) //no change
|
|
||||||
{
|
|
||||||
if (com_searchpaths->path_id > 1) { //current game not id1
|
|
||||||
if (*p2 && com_searchpaths->path_id == 2) {
|
|
||||||
// rely on QuakeSpasm extension treating '-game missionpack'
|
|
||||||
// as '-missionpack', otherwise would be a mess
|
|
||||||
if (!q_strcasecmp(p, &p2[1]))
|
|
||||||
goto _same;
|
|
||||||
Con_Printf("reloading game \"%s\" with \"%s\" support\n", p, &p2[1]);
|
|
||||||
}
|
}
|
||||||
else if (!*p2 && com_searchpaths->path_id > 2)
|
else if (*p == '-')
|
||||||
Con_Printf("reloading game \"%s\" without mission pack support\n", p);
|
continue;
|
||||||
else goto _same;
|
|
||||||
}
|
if (!*p || !strcmp(p, ".") || strstr(p, "..") || strstr(p, "/") || strstr(p, "\\") || strstr(p, ":"))
|
||||||
else { _same:
|
{
|
||||||
Con_Printf("\"game\" is already \"%s\"\n", COM_SkipPath(com_gamedir));
|
Con_Printf ("gamedir should be a single directory name, not a path\n");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!q_strcasecmp(p, GAMENAME))
|
||||||
|
continue; //don't add id1, its not interesting enough.
|
||||||
|
|
||||||
|
if (*paths)
|
||||||
|
q_strlcat(paths, ";", sizeof(paths));
|
||||||
|
q_strlcat(paths, p, sizeof(paths));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!q_strcasecmp(paths, COM_GetGameNames(true)))
|
||||||
|
{
|
||||||
|
Con_Printf("\"game\" is already \"%s\"\n", COM_GetGameNames(true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
com_modified = true;
|
com_modified = true;
|
||||||
|
|
||||||
//Kill the server
|
//Kill the server
|
||||||
|
@ -2146,57 +2509,10 @@ static void COM_Game_f (void)
|
||||||
Host_ShutdownServer(true);
|
Host_ShutdownServer(true);
|
||||||
|
|
||||||
//Write config file
|
//Write config file
|
||||||
|
//fixme -- writing configs without reloading when switching between many mods is SERIOUSLY dangerous. ignore if no 'exec default.cfg' commands were used?
|
||||||
Host_WriteConfiguration ();
|
Host_WriteConfiguration ();
|
||||||
|
|
||||||
//Kill the extra game if it is loaded
|
COM_ResetGameDirectories(paths);
|
||||||
while (com_searchpaths != com_base_searchpaths)
|
|
||||||
{
|
|
||||||
if (com_searchpaths->pack)
|
|
||||||
{
|
|
||||||
Sys_FileClose (com_searchpaths->pack->handle);
|
|
||||||
Z_Free (com_searchpaths->pack->files);
|
|
||||||
Z_Free (com_searchpaths->pack);
|
|
||||||
}
|
|
||||||
search = com_searchpaths->next;
|
|
||||||
Z_Free (com_searchpaths);
|
|
||||||
com_searchpaths = search;
|
|
||||||
}
|
|
||||||
hipnotic = false;
|
|
||||||
rogue = false;
|
|
||||||
standard_quake = true;
|
|
||||||
|
|
||||||
if (q_strcasecmp(p, GAMENAME)) //game is not id1
|
|
||||||
{
|
|
||||||
if (*p2) {
|
|
||||||
COM_AddGameDirectory (com_basedir, &p2[1]);
|
|
||||||
standard_quake = false;
|
|
||||||
if (!strcmp(p2,"-hipnotic") || !strcmp(p2,"-quoth"))
|
|
||||||
hipnotic = true;
|
|
||||||
else if (!strcmp(p2,"-rogue"))
|
|
||||||
rogue = true;
|
|
||||||
if (q_strcasecmp(p, &p2[1])) //don't load twice
|
|
||||||
COM_AddGameDirectory (com_basedir, p);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
COM_AddGameDirectory (com_basedir, p);
|
|
||||||
// QuakeSpasm extension: treat '-game missionpack' as '-missionpack'
|
|
||||||
if (!q_strcasecmp(p,"hipnotic") || !q_strcasecmp(p,"quoth")) {
|
|
||||||
hipnotic = true;
|
|
||||||
standard_quake = false;
|
|
||||||
}
|
|
||||||
else if (!q_strcasecmp(p,"rogue")) {
|
|
||||||
rogue = true;
|
|
||||||
standard_quake = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // just update com_gamedir
|
|
||||||
{
|
|
||||||
q_snprintf (com_gamedir, sizeof(com_gamedir), "%s/%s",
|
|
||||||
(host_parms->userdir != host_parms->basedir)?
|
|
||||||
host_parms->userdir : com_basedir,
|
|
||||||
GAMENAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
//clear out and reload appropriate data
|
//clear out and reload appropriate data
|
||||||
Cache_Flush ();
|
Cache_Flush ();
|
||||||
|
@ -2210,14 +2526,14 @@ static void COM_Game_f (void)
|
||||||
ExtraMaps_NewGame ();
|
ExtraMaps_NewGame ();
|
||||||
DemoList_Rebuild ();
|
DemoList_Rebuild ();
|
||||||
|
|
||||||
Con_Printf("\"game\" changed to \"%s\"\n", COM_SkipPath(com_gamedir));
|
Con_Printf("\"game\" changed to \"%s\"\n", COM_GetGameNames(true));
|
||||||
|
|
||||||
VID_Lock ();
|
VID_Lock ();
|
||||||
Cbuf_AddText ("exec quake.rc\n");
|
Cbuf_AddText ("exec quake.rc\n");
|
||||||
Cbuf_AddText ("vid_unlock\n");
|
Cbuf_AddText ("vid_unlock\n");
|
||||||
}
|
}
|
||||||
else //Diplay the current gamedir
|
else //Diplay the current gamedir
|
||||||
Con_Printf("\"game\" is \"%s\"\n", COM_SkipPath(com_gamedir));
|
Con_Printf("\"game\" is \"%s\"\n", COM_GetGameNames(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2228,11 +2544,14 @@ COM_InitFilesystem
|
||||||
void COM_InitFilesystem (void) //johnfitz -- modified based on topaz's tutorial
|
void COM_InitFilesystem (void) //johnfitz -- modified based on topaz's tutorial
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
Cvar_RegisterVariable (&allow_download);
|
||||||
Cvar_RegisterVariable (®istered);
|
Cvar_RegisterVariable (®istered);
|
||||||
Cvar_RegisterVariable (&cmdline);
|
Cvar_RegisterVariable (&cmdline);
|
||||||
Cmd_AddCommand ("path", COM_Path_f);
|
Cmd_AddCommand ("path", COM_Path_f);
|
||||||
Cmd_AddCommand ("game", COM_Game_f); //johnfitz
|
Cmd_AddCommand ("game", COM_Game_f); //johnfitz
|
||||||
|
Cmd_AddCommand ("gamedir", COM_Game_f); //Spike -- alternative name for it, consistent with quakeworld and a few other engines
|
||||||
|
|
||||||
i = COM_CheckParm ("-basedir");
|
i = COM_CheckParm ("-basedir");
|
||||||
if (i && i < com_argc-1)
|
if (i && i < com_argc-1)
|
||||||
|
@ -2246,46 +2565,36 @@ void COM_InitFilesystem (void) //johnfitz -- modified based on topaz's tutorial
|
||||||
com_basedir[j-1] = 0;
|
com_basedir[j-1] = 0;
|
||||||
|
|
||||||
// start up with GAMENAME by default (id1)
|
// start up with GAMENAME by default (id1)
|
||||||
COM_AddGameDirectory (com_basedir, GAMENAME);
|
COM_AddGameDirectory (GAMENAME);
|
||||||
|
|
||||||
/* this is the end of our base searchpath:
|
/* this is the end of our base searchpath:
|
||||||
* any set gamedirs, such as those from -game command line
|
* any set gamedirs, such as those from -game command line
|
||||||
* arguments or by the 'game' console command will be freed
|
* arguments or by the 'game' console command will be freed
|
||||||
* up to here upon a new game command. */
|
* up to here upon a new game command. */
|
||||||
com_base_searchpaths = com_searchpaths;
|
com_base_searchpaths = com_searchpaths;
|
||||||
|
COM_ResetGameDirectories("");
|
||||||
|
|
||||||
// add mission pack requests (only one should be specified)
|
// add mission pack requests (only one should be specified)
|
||||||
if (COM_CheckParm ("-rogue"))
|
if (COM_CheckParm ("-rogue"))
|
||||||
COM_AddGameDirectory (com_basedir, "rogue");
|
COM_AddGameDirectory ("rogue");
|
||||||
if (COM_CheckParm ("-hipnotic"))
|
if (COM_CheckParm ("-hipnotic"))
|
||||||
COM_AddGameDirectory (com_basedir, "hipnotic");
|
COM_AddGameDirectory ("hipnotic");
|
||||||
if (COM_CheckParm ("-quoth"))
|
if (COM_CheckParm ("-quoth"))
|
||||||
COM_AddGameDirectory (com_basedir, "quoth");
|
COM_AddGameDirectory ("quoth");
|
||||||
|
|
||||||
|
|
||||||
i = COM_CheckParm ("-game");
|
for(i = 0;;)
|
||||||
if (i && i < com_argc-1)
|
|
||||||
{
|
{
|
||||||
const char *p = com_argv[i + 1];
|
i = COM_CheckParmNext (i, "-game");
|
||||||
if (!*p || !strcmp(p, ".") || strstr(p, "..") || strstr(p, "/") || strstr(p, "\\") || strstr(p, ":"))
|
if (!i || i >= com_argc-1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
p = com_argv[i + 1];
|
||||||
|
if (!*p || !strcmp(p, ".") || strstr(p, "..") || *p=='/' || *p=='\\' || strstr(p, ":"))
|
||||||
Sys_Error ("gamedir should be a single directory name, not a path\n");
|
Sys_Error ("gamedir should be a single directory name, not a path\n");
|
||||||
com_modified = true;
|
com_modified = true;
|
||||||
// don't load mission packs twice
|
if (p != NULL)
|
||||||
if (COM_CheckParm ("-rogue") && !q_strcasecmp(p, "rogue")) p = NULL;
|
COM_AddGameDirectory (p);
|
||||||
if (COM_CheckParm ("-hipnotic") && !q_strcasecmp(p, "hipnotic")) p = NULL;
|
|
||||||
if (COM_CheckParm ("-quoth") && !q_strcasecmp(p, "quoth")) p = NULL;
|
|
||||||
if (p != NULL) {
|
|
||||||
COM_AddGameDirectory (com_basedir, p);
|
|
||||||
// QuakeSpasm extension: treat '-game missionpack' as '-missionpack'
|
|
||||||
if (!q_strcasecmp(p,"rogue")) {
|
|
||||||
rogue = true;
|
|
||||||
standard_quake = false;
|
|
||||||
}
|
|
||||||
if (!q_strcasecmp(p,"hipnotic") || !q_strcasecmp(p,"quoth")) {
|
|
||||||
hipnotic = true;
|
|
||||||
standard_quake = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COM_CheckRegistered ();
|
COM_CheckRegistered ();
|
||||||
|
@ -2461,3 +2770,69 @@ long FS_filelength (fshandle_t *fh)
|
||||||
return fh->length;
|
return fh->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//for compat with dpp7 protocols, and mods that cba to precache things.
|
||||||
|
void COM_Effectinfo_Enumerate(int (*cb)(const char *pname))
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char *f, *e;
|
||||||
|
char *buf;
|
||||||
|
static const char *dpnames[] =
|
||||||
|
{
|
||||||
|
"TE_GUNSHOT",
|
||||||
|
"TE_GUNSHOTQUAD",
|
||||||
|
"TE_SPIKE",
|
||||||
|
"TE_SPIKEQUAD",
|
||||||
|
"TE_SUPERSPIKE",
|
||||||
|
"TE_SUPERSPIKEQUAD",
|
||||||
|
"TE_WIZSPIKE",
|
||||||
|
"TE_KNIGHTSPIKE",
|
||||||
|
"TE_EXPLOSION",
|
||||||
|
"TE_EXPLOSIONQUAD",
|
||||||
|
"TE_TAREXPLOSION",
|
||||||
|
"TE_TELEPORT",
|
||||||
|
"TE_LAVASPLASH",
|
||||||
|
"TE_SMALLFLASH",
|
||||||
|
"TE_FLAMEJET",
|
||||||
|
"EF_FLAME",
|
||||||
|
"TE_BLOOD",
|
||||||
|
"TE_SPARK",
|
||||||
|
"TE_PLASMABURN",
|
||||||
|
"TE_TEI_G3",
|
||||||
|
"TE_TEI_SMOKE",
|
||||||
|
"TE_TEI_BIGEXPLOSION",
|
||||||
|
"TE_TEI_PLASMAHIT",
|
||||||
|
"EF_STARDUST",
|
||||||
|
"TR_ROCKET",
|
||||||
|
"TR_GRENADE",
|
||||||
|
"TR_BLOOD",
|
||||||
|
"TR_WIZSPIKE",
|
||||||
|
"TR_SLIGHTBLOOD",
|
||||||
|
"TR_KNIGHTSPIKE",
|
||||||
|
"TR_VORESPIKE",
|
||||||
|
"TR_NEHAHRASMOKE",
|
||||||
|
"TR_NEXUIZPLASMA",
|
||||||
|
"TR_GLOWTRAIL",
|
||||||
|
"SVC_PARTICLE",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
buf = (char*)COM_LoadMallocFile("effectinfo.txt", NULL);
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; dpnames[i]; i++)
|
||||||
|
cb(dpnames[i]);
|
||||||
|
|
||||||
|
for (f = buf; f; f = e)
|
||||||
|
{
|
||||||
|
e = COM_Parse (f);
|
||||||
|
if (!strcmp(com_token, "effect"))
|
||||||
|
{
|
||||||
|
e = COM_Parse (e);
|
||||||
|
cb(com_token);
|
||||||
|
}
|
||||||
|
while (e && *e && *e != '\n')
|
||||||
|
e++;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
|
@ -103,6 +103,8 @@ void MSG_WriteString (sizebuf_t *sb, const char *s);
|
||||||
void MSG_WriteCoord (sizebuf_t *sb, float f, unsigned int flags);
|
void MSG_WriteCoord (sizebuf_t *sb, float f, unsigned int flags);
|
||||||
void MSG_WriteAngle (sizebuf_t *sb, float f, unsigned int flags);
|
void MSG_WriteAngle (sizebuf_t *sb, float f, unsigned int flags);
|
||||||
void MSG_WriteAngle16 (sizebuf_t *sb, float f, unsigned int flags); //johnfitz
|
void MSG_WriteAngle16 (sizebuf_t *sb, float f, unsigned int flags); //johnfitz
|
||||||
|
struct entity_state_s;
|
||||||
|
void MSG_WriteStaticOrBaseLine(sizebuf_t *buf, int idx, struct entity_state_s *state, unsigned int protocol_pext2, unsigned int protocol, unsigned int protocolflags); //spike
|
||||||
|
|
||||||
extern int msg_readcount;
|
extern int msg_readcount;
|
||||||
extern qboolean msg_badread; // set if a read goes beyond end of message
|
extern qboolean msg_badread; // set if a read goes beyond end of message
|
||||||
|
@ -118,6 +120,9 @@ const char *MSG_ReadString (void);
|
||||||
float MSG_ReadCoord (unsigned int flags);
|
float MSG_ReadCoord (unsigned int flags);
|
||||||
float MSG_ReadAngle (unsigned int flags);
|
float MSG_ReadAngle (unsigned int flags);
|
||||||
float MSG_ReadAngle16 (unsigned int flags); //johnfitz
|
float MSG_ReadAngle16 (unsigned int flags); //johnfitz
|
||||||
|
byte *MSG_ReadData (unsigned int length); // spike
|
||||||
|
|
||||||
|
void COM_Effectinfo_Enumerate(int (*cb)(const char *pname)); //spike -- for dp compat
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
@ -171,6 +176,7 @@ extern int safemode;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int COM_CheckParm (const char *parm);
|
int COM_CheckParm (const char *parm);
|
||||||
|
int COM_CheckParmNext (int last, const char *parm);
|
||||||
|
|
||||||
void COM_Init (void);
|
void COM_Init (void);
|
||||||
void COM_InitArgv (int argc, char **argv);
|
void COM_InitArgv (int argc, char **argv);
|
||||||
|
@ -180,6 +186,7 @@ const char *COM_SkipPath (const char *pathname);
|
||||||
void COM_StripExtension (const char *in, char *out, size_t outsize);
|
void COM_StripExtension (const char *in, char *out, size_t outsize);
|
||||||
void COM_FileBase (const char *in, char *out, size_t outsize);
|
void COM_FileBase (const char *in, char *out, size_t outsize);
|
||||||
void COM_AddExtension (char *path, const char *extension, size_t len);
|
void COM_AddExtension (char *path, const char *extension, size_t len);
|
||||||
|
qboolean COM_DownloadNameOkay(const char *filename);
|
||||||
#if 0 /* COM_DefaultExtension can be dangerous */
|
#if 0 /* COM_DefaultExtension can be dangerous */
|
||||||
void COM_DefaultExtension (char *path, const char *extension, size_t len);
|
void COM_DefaultExtension (char *path, const char *extension, size_t len);
|
||||||
#endif
|
#endif
|
||||||
|
@ -198,6 +205,7 @@ typedef struct
|
||||||
{
|
{
|
||||||
char name[MAX_QPATH];
|
char name[MAX_QPATH];
|
||||||
int filepos, filelen;
|
int filepos, filelen;
|
||||||
|
int deflatedsize;
|
||||||
} packfile_t;
|
} packfile_t;
|
||||||
|
|
||||||
typedef struct pack_s
|
typedef struct pack_s
|
||||||
|
@ -228,6 +236,12 @@ extern char com_basedir[MAX_OSPATH];
|
||||||
extern char com_gamedir[MAX_OSPATH];
|
extern char com_gamedir[MAX_OSPATH];
|
||||||
extern int file_from_pak; // global indicating that file came from a pak
|
extern int file_from_pak; // global indicating that file came from a pak
|
||||||
|
|
||||||
|
const char *COM_GetGameNames(qboolean full);
|
||||||
|
qboolean COM_GameDirMatches(const char *tdirs);
|
||||||
|
|
||||||
|
pack_t *FSZIP_LoadArchive (const char *packfile);
|
||||||
|
FILE *FSZIP_Deflate(FILE *src, int srcsize, int outsize);
|
||||||
|
|
||||||
void COM_WriteFile (const char *filename, const void *data, int len);
|
void COM_WriteFile (const char *filename, const void *data, int len);
|
||||||
int COM_OpenFile (const char *filename, int *handle, unsigned int *path_id);
|
int COM_OpenFile (const char *filename, int *handle, unsigned int *path_id);
|
||||||
int COM_FOpenFile (const char *filename, FILE **file, unsigned int *path_id);
|
int COM_FOpenFile (const char *filename, FILE **file, unsigned int *path_id);
|
||||||
|
|
152
Quake/console.c
152
Quake/console.c
|
@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
|
#include "q_ctype.h"
|
||||||
|
|
||||||
int con_linewidth;
|
int con_linewidth;
|
||||||
|
|
||||||
|
@ -54,6 +55,9 @@ cvar_t con_logcenterprint = {"con_logcenterprint", "1", CVAR_NONE}; //johnfitz
|
||||||
|
|
||||||
char con_lastcenterstring[1024]; //johnfitz
|
char con_lastcenterstring[1024]; //johnfitz
|
||||||
|
|
||||||
|
void (*con_redirect_flush)(const char *buffer); //call this to flush the redirection buffer (for rcon)
|
||||||
|
char con_redirect_buffer[8192];
|
||||||
|
|
||||||
#define NUM_CON_TIMES 4
|
#define NUM_CON_TIMES 4
|
||||||
float con_times[NUM_CON_TIMES]; // realtime time the line was generated
|
float con_times[NUM_CON_TIMES]; // realtime time the line was generated
|
||||||
// for transparent notify lines
|
// for transparent notify lines
|
||||||
|
@ -358,6 +362,17 @@ static void Con_Linefeed (void)
|
||||||
Q_memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
|
Q_memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ishex(c) ((c>='0' && c<= '9') || (c>='a' && c<='f') || (c>='A' && c<='F'))
|
||||||
|
static int dehex(char c)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c-'0';
|
||||||
|
if (c >= 'A' && c <= 'F')
|
||||||
|
return c-('A'-10);
|
||||||
|
if (c >= 'a' && c <= 'f')
|
||||||
|
return c-('a'-10);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
Con_Print
|
Con_Print
|
||||||
|
@ -395,6 +410,95 @@ static void Con_Print (const char *txt)
|
||||||
|
|
||||||
while ( (c = *txt) )
|
while ( (c = *txt) )
|
||||||
{
|
{
|
||||||
|
if (c == '^' && pr_checkextension.value)
|
||||||
|
{ //parse markup like FTE/DP might.
|
||||||
|
switch(txt[1])
|
||||||
|
{
|
||||||
|
case '^': //doubled up char for escaping.
|
||||||
|
txt++;
|
||||||
|
break;
|
||||||
|
case '0': //black
|
||||||
|
case '1': //red
|
||||||
|
case '2': //green
|
||||||
|
case '3': //yellow
|
||||||
|
case '4': //blue
|
||||||
|
case '5': //cyan
|
||||||
|
case '6': //magenta
|
||||||
|
case '7': //white
|
||||||
|
case '8': //white+half-alpha
|
||||||
|
case '9': //grey
|
||||||
|
case 'h': //toggle half-alpha
|
||||||
|
case 'b': //blink
|
||||||
|
case 'd': //reset to defaults (fixme: should reset ^m without resetting \1)
|
||||||
|
case 's': //modstack push
|
||||||
|
case 'r': //modstack restore
|
||||||
|
txt+=2;
|
||||||
|
continue;
|
||||||
|
case 'x': //RGB 12-bit colour
|
||||||
|
if (ishex(txt[2]) && ishex(txt[3]) && ishex(txt[4]))
|
||||||
|
{
|
||||||
|
txt+=4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break; //malformed
|
||||||
|
case '[': //start fte's ^[text\key\value\key\value^] links
|
||||||
|
case ']': //end link
|
||||||
|
break; //fixme... skip the keys, recolour properly, etc
|
||||||
|
// txt+=2;
|
||||||
|
// continue;
|
||||||
|
case '&':
|
||||||
|
if ((ishex(txt[2])||txt[2]=='-') && (ishex(txt[3])||txt[3]=='-'))
|
||||||
|
{ //ignore fte's fore/back ansi colours
|
||||||
|
txt += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break; //malformed
|
||||||
|
case 'm': //toggle masking.
|
||||||
|
txt+=2;
|
||||||
|
mask ^= 128;
|
||||||
|
continue;
|
||||||
|
case 'U': //ucs-2 unicode codepoint
|
||||||
|
if (ishex(txt[2]) && ishex(txt[3]) && ishex(txt[4]) && ishex(txt[5]))
|
||||||
|
{
|
||||||
|
c = (dehex(txt[2])<<12) | (dehex(txt[3])<<8) | (dehex(txt[4])<<4) | dehex(txt[5]);
|
||||||
|
txt += 6-1;
|
||||||
|
|
||||||
|
if (c >= 0xe000 && c <= 0xe0ff)
|
||||||
|
c &= 0xff; //private-use 0xE0XX maps to quake's chars
|
||||||
|
else if (c >= 0x20 && c <= 0x7f)
|
||||||
|
c &= 0x7f; //ascii is okay too.
|
||||||
|
else
|
||||||
|
c = '?'; //otherwise its some unicode char that we don't know how to handle.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break; //malformed
|
||||||
|
case '{': //full unicode codepoint, for chars up to 0x10ffff
|
||||||
|
txt += 2;
|
||||||
|
c = 0; //no idea
|
||||||
|
while(*txt)
|
||||||
|
{
|
||||||
|
if (*txt == '}')
|
||||||
|
{
|
||||||
|
txt++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ishex(*txt))
|
||||||
|
break;
|
||||||
|
c<<=4;
|
||||||
|
c |= dehex(*txt++);
|
||||||
|
}
|
||||||
|
txt--; // for the ++ below
|
||||||
|
|
||||||
|
if (c >= 0xe000 && c <= 0xe0ff)
|
||||||
|
c &= 0xff; //private-use 0xE0XX maps to quake's chars
|
||||||
|
else if (c >= 0x20 && c <= 0x7f)
|
||||||
|
c &= 0x7f; //ascii is okay too.
|
||||||
|
else
|
||||||
|
c = '?'; //otherwise its some unicode char that we don't know how to handle.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (c <= ' ')
|
if (c <= ' ')
|
||||||
{
|
{
|
||||||
boundary = true;
|
boundary = true;
|
||||||
|
@ -489,6 +593,9 @@ void Con_Printf (const char *fmt, ...)
|
||||||
q_vsnprintf (msg, sizeof(msg), fmt, argptr);
|
q_vsnprintf (msg, sizeof(msg), fmt, argptr);
|
||||||
va_end (argptr);
|
va_end (argptr);
|
||||||
|
|
||||||
|
if (con_redirect_flush)
|
||||||
|
q_strlcat(con_redirect_buffer, msg, sizeof(con_redirect_buffer));
|
||||||
|
|
||||||
// also echo to debugging console
|
// also echo to debugging console
|
||||||
Sys_Printf ("%s", msg);
|
Sys_Printf ("%s", msg);
|
||||||
|
|
||||||
|
@ -533,15 +640,17 @@ void Con_DWarning (const char *fmt, ...)
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
char msg[MAXPRINTMSG];
|
char msg[MAXPRINTMSG];
|
||||||
|
|
||||||
if (!developer.value)
|
if (developer.value >= 2)
|
||||||
return; // don't confuse non-developers with techie stuff...
|
{ // don't confuse non-developers with techie stuff...
|
||||||
|
// (this is limit exceeded warnings)
|
||||||
|
|
||||||
va_start (argptr, fmt);
|
va_start (argptr, fmt);
|
||||||
q_vsnprintf (msg, sizeof(msg), fmt, argptr);
|
q_vsnprintf (msg, sizeof(msg), fmt, argptr);
|
||||||
va_end (argptr);
|
va_end (argptr);
|
||||||
|
|
||||||
Con_SafePrintf ("\x02Warning: ");
|
Con_SafePrintf ("\x02Warning: ");
|
||||||
Con_Printf ("%s", msg);
|
Con_Printf ("%s", msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -695,6 +804,18 @@ void Con_LogCenterPrint (const char *str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qboolean Con_IsRedirected(void)
|
||||||
|
{
|
||||||
|
return !!con_redirect_flush;
|
||||||
|
}
|
||||||
|
void Con_Redirect(void(*flush)(const char *))
|
||||||
|
{
|
||||||
|
if (con_redirect_flush)
|
||||||
|
con_redirect_flush(con_redirect_buffer);
|
||||||
|
*con_redirect_buffer = 0;
|
||||||
|
con_redirect_flush = flush;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
|
@ -717,12 +838,6 @@ tab_t *tablist;
|
||||||
|
|
||||||
//defs from elsewhere
|
//defs from elsewhere
|
||||||
extern qboolean keydown[256];
|
extern qboolean keydown[256];
|
||||||
typedef struct cmd_function_s
|
|
||||||
{
|
|
||||||
struct cmd_function_s *next;
|
|
||||||
const char *name;
|
|
||||||
xcommand_t function;
|
|
||||||
} cmd_function_t;
|
|
||||||
extern cmd_function_t *cmd_functions;
|
extern cmd_function_t *cmd_functions;
|
||||||
#define MAX_ALIAS_NAME 32
|
#define MAX_ALIAS_NAME 32
|
||||||
typedef struct cmdalias_s
|
typedef struct cmdalias_s
|
||||||
|
@ -763,7 +878,7 @@ void AddToTabList (const char *name, const char *type)
|
||||||
// find max common between bash_partial and name
|
// find max common between bash_partial and name
|
||||||
i_bash = bash_partial;
|
i_bash = bash_partial;
|
||||||
i_name = name;
|
i_name = name;
|
||||||
while (*i_bash && (*i_bash == *i_name))
|
while (*i_bash && (q_tolower(*i_bash) == q_tolower(*i_name)))
|
||||||
{
|
{
|
||||||
i_bash++;
|
i_bash++;
|
||||||
i_name++;
|
i_name++;
|
||||||
|
@ -901,15 +1016,15 @@ void BuildTabList (const char *partial)
|
||||||
|
|
||||||
cvar = Cvar_FindVarAfter ("", CVAR_NONE);
|
cvar = Cvar_FindVarAfter ("", CVAR_NONE);
|
||||||
for ( ; cvar ; cvar=cvar->next)
|
for ( ; cvar ; cvar=cvar->next)
|
||||||
if (!Q_strncmp (partial, cvar->name, len))
|
if (!q_strncasecmp (partial, cvar->name, len))
|
||||||
AddToTabList (cvar->name, "cvar");
|
AddToTabList (cvar->name, "cvar");
|
||||||
|
|
||||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||||
if (!Q_strncmp (partial,cmd->name, len))
|
if (!q_strncasecmp (partial,cmd->name, len) && cmd->srctype != src_server)
|
||||||
AddToTabList (cmd->name, "command");
|
AddToTabList (cmd->name, "command");
|
||||||
|
|
||||||
for (alias=cmd_alias ; alias ; alias=alias->next)
|
for (alias=cmd_alias ; alias ; alias=alias->next)
|
||||||
if (!Q_strncmp (partial, alias->name, len))
|
if (!q_strncasecmp (partial, alias->name, len))
|
||||||
AddToTabList (alias->name, "alias");
|
AddToTabList (alias->name, "alias");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1184,7 +1299,7 @@ void Con_DrawConsole (int lines, qboolean drawinput)
|
||||||
{
|
{
|
||||||
int i, x, y, j, sb, rows;
|
int i, x, y, j, sb, rows;
|
||||||
const char *text;
|
const char *text;
|
||||||
char ver[32];
|
const char *ver = ENGINE_NAME_AND_VER;
|
||||||
|
|
||||||
if (lines <= 0)
|
if (lines <= 0)
|
||||||
return;
|
return;
|
||||||
|
@ -1227,7 +1342,6 @@ void Con_DrawConsole (int lines, qboolean drawinput)
|
||||||
|
|
||||||
//draw version number in bottom right
|
//draw version number in bottom right
|
||||||
y += 8;
|
y += 8;
|
||||||
q_snprintf (ver, sizeof(ver), "QuakeSpasm " QUAKESPASM_VER_STRING);
|
|
||||||
for (x = 0; x < (int)strlen(ver); x++)
|
for (x = 0; x < (int)strlen(ver); x++)
|
||||||
Draw_Character ((con_linewidth - strlen(ver) + x + 2)<<3, y, ver[x] /*+ 128*/);
|
Draw_Character ((con_linewidth - strlen(ver) + x + 2)<<3, y, ver[x] /*+ 128*/);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,8 @@ void Con_SafePrintf (const char *fmt, ...) FUNC_PRINTF(1,2);
|
||||||
void Con_DrawNotify (void);
|
void Con_DrawNotify (void);
|
||||||
void Con_ClearNotify (void);
|
void Con_ClearNotify (void);
|
||||||
void Con_ToggleConsole_f (void);
|
void Con_ToggleConsole_f (void);
|
||||||
|
qboolean Con_IsRedirected(void); //returns true if its redirected. this generally means that things are a little more verbose.
|
||||||
|
void Con_Redirect(void(*flush)(const char *text));
|
||||||
|
|
||||||
void Con_NotifyBox (const char *text); // during startup for sound / cd warnings
|
void Con_NotifyBox (const char *text); // during startup for sound / cd warnings
|
||||||
|
|
||||||
|
|
73
Quake/cvar.c
73
Quake/cvar.c
|
@ -101,6 +101,40 @@ void Cvar_Inc_f (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
Cvar_Set_f -- spike
|
||||||
|
|
||||||
|
both set+seta commands
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
void Cvar_Set_f (void)
|
||||||
|
{
|
||||||
|
//q2: set name value flags
|
||||||
|
//dp: set name value description
|
||||||
|
//fte: set name some freeform value with spaces or whatever //description
|
||||||
|
//to avoid politics, its easier to just stick with name+value only.
|
||||||
|
//that leaves someone else free to pick a standard for what to do with extra args.
|
||||||
|
const char *varname = Cmd_Argv(1);
|
||||||
|
const char *varvalue = Cmd_Argv(2);
|
||||||
|
cvar_t *var;
|
||||||
|
if (Cmd_Argc() < 3)
|
||||||
|
{
|
||||||
|
Con_Printf("%s <cvar> <value>\n", Cmd_Argv(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Cmd_Argc() > 3)
|
||||||
|
{
|
||||||
|
Con_Warning("%s \"%s\" command with extra args\n", Cmd_Argv(0), varname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var = Cvar_Create(varname, varvalue);
|
||||||
|
Cvar_SetQuick(var, varvalue);
|
||||||
|
|
||||||
|
if (!strcmp(Cmd_Argv(0), "seta"))
|
||||||
|
var->flags |= CVAR_ARCHIVE|CVAR_SETA;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
Cvar_Toggle_f -- johnfitz
|
Cvar_Toggle_f -- johnfitz
|
||||||
|
@ -232,6 +266,8 @@ void Cvar_Init (void)
|
||||||
Cmd_AddCommand ("reset", Cvar_Reset_f);
|
Cmd_AddCommand ("reset", Cvar_Reset_f);
|
||||||
Cmd_AddCommand ("resetall", Cvar_ResetAll_f);
|
Cmd_AddCommand ("resetall", Cvar_ResetAll_f);
|
||||||
Cmd_AddCommand ("resetcfg", Cvar_ResetCfg_f);
|
Cmd_AddCommand ("resetcfg", Cvar_ResetCfg_f);
|
||||||
|
Cmd_AddCommand ("set", Cvar_Set_f);
|
||||||
|
Cmd_AddCommand ("seta", Cvar_Set_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
@ -426,6 +462,8 @@ void Cvar_SetQuick (cvar_t *var, const char *value)
|
||||||
|
|
||||||
if (var->callback)
|
if (var->callback)
|
||||||
var->callback (var);
|
var->callback (var);
|
||||||
|
if (var->flags & CVAR_AUTOCVAR)
|
||||||
|
PR_AutoCvarChanged(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cvar_SetValueQuick (cvar_t *var, const float value)
|
void Cvar_SetValueQuick (cvar_t *var, const float value)
|
||||||
|
@ -588,6 +626,34 @@ void Cvar_RegisterVariable (cvar_t *variable)
|
||||||
variable->flags |= CVAR_ROM;
|
variable->flags |= CVAR_ROM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
Cvar_Create -- spike
|
||||||
|
|
||||||
|
Creates a cvar if it does not already exist, otherwise does nothing.
|
||||||
|
Must not be used until after all other cvars are registered.
|
||||||
|
Cvar will be persistent.
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
cvar_t *Cvar_Create (const char *name, const char *value)
|
||||||
|
{
|
||||||
|
cvar_t *newvar;
|
||||||
|
newvar = Cvar_FindVar(name);
|
||||||
|
if (newvar)
|
||||||
|
return newvar; //already exists.
|
||||||
|
if (Cmd_Exists (name))
|
||||||
|
return NULL; //error! panic! oh noes!
|
||||||
|
|
||||||
|
newvar = Z_Malloc(sizeof(cvar_t) + strlen(name)+1);
|
||||||
|
newvar->name = (char*)(newvar+1);
|
||||||
|
strcpy((char*)(newvar+1), name);
|
||||||
|
newvar->flags = CVAR_USERDEFINED;
|
||||||
|
|
||||||
|
newvar->string = value;
|
||||||
|
Cvar_RegisterVariable(newvar);
|
||||||
|
return newvar;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
Cvar_SetCallback
|
Cvar_SetCallback
|
||||||
|
@ -626,6 +692,9 @@ qboolean Cvar_Command (void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Con_IsRedirected())
|
||||||
|
Con_Printf ("changing \"%s\" from \"%s\" to \"%s\"\n", v->name, v->string, Cmd_Argv(1));
|
||||||
|
|
||||||
Cvar_Set (v->name, Cmd_Argv(1));
|
Cvar_Set (v->name, Cmd_Argv(1));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -646,7 +715,11 @@ void Cvar_WriteVariables (FILE *f)
|
||||||
for (var = cvar_vars ; var ; var = var->next)
|
for (var = cvar_vars ; var ; var = var->next)
|
||||||
{
|
{
|
||||||
if (var->flags & CVAR_ARCHIVE)
|
if (var->flags & CVAR_ARCHIVE)
|
||||||
|
{
|
||||||
|
if (var->flags & (CVAR_USERDEFINED|CVAR_SETA))
|
||||||
|
fprintf (f, "seta ");
|
||||||
fprintf (f, "%s \"%s\"\n", var->name, var->string);
|
fprintf (f, "%s \"%s\"\n", var->name, var->string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
Quake/cvar.h
14
Quake/cvar.h
|
@ -63,16 +63,19 @@ interface from being ambiguous.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CVAR_NONE 0
|
#define CVAR_NONE 0
|
||||||
#define CVAR_ARCHIVE (1U << 0) // if set, causes it to be saved to config
|
#define CVAR_ARCHIVE (1U << 0) // if set, causes it to be saved to config
|
||||||
#define CVAR_NOTIFY (1U << 1) // changes will be broadcasted to all players (q1)
|
#define CVAR_NOTIFY (1U << 1) // changes will be broadcasted to all players (q1)
|
||||||
#define CVAR_SERVERINFO (1U << 2) // added to serverinfo will be sent to clients (q1/net_dgrm.c and qwsv)
|
#define CVAR_SERVERINFO (1U << 2) // added to serverinfo will be sent to clients (q1/net_dgrm.c and qwsv)
|
||||||
#define CVAR_USERINFO (1U << 3) // added to userinfo, will be sent to server (qwcl)
|
#define CVAR_USERINFO (1U << 3) // added to userinfo, will be sent to server (qwcl)
|
||||||
#define CVAR_CHANGED (1U << 4)
|
#define CVAR_CHANGED (1U << 4)
|
||||||
#define CVAR_ROM (1U << 6)
|
#define CVAR_ROM (1U << 6)
|
||||||
#define CVAR_LOCKED (1U << 8) // locked temporarily
|
#define CVAR_LOCKED (1U << 8) // locked temporarily
|
||||||
#define CVAR_REGISTERED (1U << 10) // the var is added to the list of variables
|
#define CVAR_REGISTERED (1U << 10) // the var is added to the list of variables
|
||||||
#define CVAR_CALLBACK (1U << 16) // var has a callback
|
#define CVAR_CALLBACK (1U << 16) // var has a callback
|
||||||
|
#define CVAR_USERDEFINED (1U << 17) // cvar was created by the user/mod, and needs to be saved a bit differently.
|
||||||
|
#define CVAR_AUTOCVAR (1U << 18) // cvar changes need to feed back to qc global changes.
|
||||||
|
#define CVAR_SETA (1U << 19) // cvar will be saved with seta.
|
||||||
|
|
||||||
|
|
||||||
typedef void (*cvarcallback_t) (struct cvar_s *);
|
typedef void (*cvarcallback_t) (struct cvar_s *);
|
||||||
|
@ -92,6 +95,9 @@ void Cvar_RegisterVariable (cvar_t *variable);
|
||||||
// registers a cvar that already has the name, string, and optionally
|
// registers a cvar that already has the name, string, and optionally
|
||||||
// the archive elements set.
|
// the archive elements set.
|
||||||
|
|
||||||
|
cvar_t *Cvar_Create (const char *name, const char *value);
|
||||||
|
//creates+registers a cvar, otherwise just returns it.
|
||||||
|
|
||||||
void Cvar_SetCallback (cvar_t *var, cvarcallback_t func);
|
void Cvar_SetCallback (cvar_t *var, cvarcallback_t func);
|
||||||
// set a callback function to the var
|
// set a callback function to the var
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,822 @@
|
||||||
|
#include "quakedef.h"
|
||||||
|
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
#include <zlib.h>
|
||||||
|
#else
|
||||||
|
#pragma message("zips supported but with no zlib")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//ZIP features:
|
||||||
|
//zip64 for huge zips, except that quakespasm's filesystem calls are all otherwise 31bit.
|
||||||
|
//utf-8 encoding support (non-utf-8 is always ibm437)
|
||||||
|
//compression mode: store
|
||||||
|
//compression mode: deflate (via zlib)
|
||||||
|
//bigendian cpus. everything misaligned.
|
||||||
|
|
||||||
|
//NOT supported:
|
||||||
|
//symlink flag (files are ignored completely)
|
||||||
|
//compression mode: deflate64
|
||||||
|
//other compression modes
|
||||||
|
//split archives
|
||||||
|
//if central dir is crypted/compressed, the archive will fail to open
|
||||||
|
//if a file is crypted/compressed, the file will (internally) be marked as corrupt
|
||||||
|
//crc verification
|
||||||
|
//infozip utf-8 name override.
|
||||||
|
//other 'extra' fields.
|
||||||
|
|
||||||
|
#define qofs_t long long
|
||||||
|
#define qofs_Make(low,high) ((unsigned int)(low) | ((qofs_t)(high)<<32))
|
||||||
|
|
||||||
|
struct zipinfo
|
||||||
|
{
|
||||||
|
unsigned int thisdisk; //this disk number
|
||||||
|
unsigned int centraldir_startdisk; //central directory starts on this disk
|
||||||
|
qofs_t centraldir_numfiles_disk; //number of files in the centraldir on this disk
|
||||||
|
qofs_t centraldir_numfiles_all; //number of files in the centraldir on all disks
|
||||||
|
qofs_t centraldir_size; //total size of the centraldir
|
||||||
|
qofs_t centraldir_offset; //start offset of the centraldir with respect to the first disk that contains it
|
||||||
|
unsigned short commentlength; //length of the comment at the end of the archive.
|
||||||
|
|
||||||
|
unsigned int zip64_centraldirend_disk; //zip64 weirdness
|
||||||
|
qofs_t zip64_centraldirend_offset;
|
||||||
|
unsigned int zip64_diskcount;
|
||||||
|
qofs_t zip64_eocdsize;
|
||||||
|
unsigned short zip64_version_madeby;
|
||||||
|
unsigned short zip64_version_needed;
|
||||||
|
|
||||||
|
unsigned short centraldir_compressionmethod;
|
||||||
|
unsigned short centraldir_algid;
|
||||||
|
|
||||||
|
qofs_t centraldir_end;
|
||||||
|
qofs_t zipoffset;
|
||||||
|
};
|
||||||
|
struct zipcentralentry
|
||||||
|
{
|
||||||
|
unsigned char *fname;
|
||||||
|
qofs_t cesize;
|
||||||
|
unsigned int flags;
|
||||||
|
time_t mtime;
|
||||||
|
|
||||||
|
//PK12
|
||||||
|
unsigned short version_madeby;
|
||||||
|
unsigned short version_needed;
|
||||||
|
unsigned short gflags;
|
||||||
|
unsigned short cmethod;
|
||||||
|
unsigned short lastmodfiletime;
|
||||||
|
unsigned short lastmodfiledate;
|
||||||
|
unsigned int crc32;
|
||||||
|
qofs_t csize;
|
||||||
|
qofs_t usize;
|
||||||
|
unsigned short fnane_len;
|
||||||
|
unsigned short extra_len;
|
||||||
|
unsigned short comment_len;
|
||||||
|
unsigned int disknum;
|
||||||
|
unsigned short iattributes;
|
||||||
|
unsigned int eattributes;
|
||||||
|
qofs_t localheaderoffset; //from start of disk
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ziplocalentry
|
||||||
|
{
|
||||||
|
//PK34
|
||||||
|
unsigned short version_needed;
|
||||||
|
unsigned short gpflags;
|
||||||
|
unsigned short cmethod;
|
||||||
|
unsigned short lastmodfiletime;
|
||||||
|
unsigned short lastmodfiledate;
|
||||||
|
unsigned int crc32;
|
||||||
|
qofs_t csize;
|
||||||
|
qofs_t usize;
|
||||||
|
unsigned short fname_len;
|
||||||
|
unsigned short extra_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LittleU2FromPtr(p) (unsigned int)((p)[0] | ((p)[1]<<8u))
|
||||||
|
#define LittleU4FromPtr(p) (unsigned int)((p)[0] | ((p)[1]<<8u) | ((p)[2]<<16u) | ((p)[3]<<24u))
|
||||||
|
#define LittleU8FromPtr(p) qofs_Make(LittleU4FromPtr(p), LittleU4FromPtr((p)+4))
|
||||||
|
|
||||||
|
#define SIZE_LOCALENTRY 30
|
||||||
|
#define SIZE_ENDOFCENTRALDIRECTORY 22
|
||||||
|
#define SIZE_ZIP64ENDOFCENTRALDIRECTORY_V1 56
|
||||||
|
#define SIZE_ZIP64ENDOFCENTRALDIRECTORY_V2 84
|
||||||
|
#define SIZE_ZIP64ENDOFCENTRALDIRECTORY SIZE_ZIP64ENDOFCENTRALDIRECTORY_V2
|
||||||
|
#define SIZE_ZIP64ENDOFCENTRALDIRECTORYLOCATOR 20
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char name[MAX_QPATH];
|
||||||
|
qofs_t localpos;
|
||||||
|
qofs_t filelen;
|
||||||
|
unsigned int crc;
|
||||||
|
unsigned int flags;
|
||||||
|
// time_t time;
|
||||||
|
} zpackfile_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int raw;
|
||||||
|
qofs_t rawsize;
|
||||||
|
|
||||||
|
size_t numfiles;
|
||||||
|
zpackfile_t *files;
|
||||||
|
} zipfile_t;
|
||||||
|
#define ZFL_DEFLATED 1 //need to use zlib
|
||||||
|
#define ZFL_STORED 2 //direct access is okay
|
||||||
|
#define ZFL_SYMLINK 4 //file is a symlink
|
||||||
|
#define ZFL_CORRUPT 8 //file is corrupt or otherwise unreadable.
|
||||||
|
#define ZFL_WEAKENCRYPT 16 //traditional zip encryption
|
||||||
|
|
||||||
|
|
||||||
|
//for zip->quake charsets
|
||||||
|
unsigned short ibmtounicode[256] =
|
||||||
|
{
|
||||||
|
0x0000,0x263A,0x263B,0x2665,0x2666,0x2663,0x2660,0x2022,0x25D8,0x25CB,0x25D9,0x2642,0x2640,0x266A,0x266B,0x263C, //0x00(non-ascii, display-only)
|
||||||
|
0x25BA,0x25C4,0x2195,0x203C,0x00B6,0x00A7,0x25AC,0x21A8,0x2191,0x2193,0x2192,0x2190,0x221F,0x2194,0x25B2,0x25BC, //0x10(non-ascii, display-only)
|
||||||
|
0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F, //0x20(ascii)
|
||||||
|
0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, //0x30(ascii)
|
||||||
|
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F, //0x40(ascii)
|
||||||
|
0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F, //0x50(ascii)
|
||||||
|
0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, //0x60(ascii)
|
||||||
|
0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x2302, //0x70(mostly ascii, one display-only)
|
||||||
|
0x00C7,0x00FC,0x00E9,0x00E2,0x00E4,0x00E0,0x00E5,0x00E7,0x00EA,0x00EB,0x00E8,0x00EF,0x00EE,0x00EC,0x00C4,0x00C5, //0x80(non-ascii, printable)
|
||||||
|
0x00C9,0x00E6,0x00C6,0x00F4,0x00F6,0x00F2,0x00FB,0x00F9,0x00FF,0x00D6,0x00DC,0x00A2,0x00A3,0x00A5,0x20A7,0x0192, //0x90(non-ascii, printable)
|
||||||
|
0x00E1,0x00ED,0x00F3,0x00FA,0x00F1,0x00D1,0x00AA,0x00BA,0x00BF,0x2310,0x00AC,0x00BD,0x00BC,0x00A1,0x00AB,0x00BB, //0xa0(non-ascii, printable)
|
||||||
|
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510, //0xb0(box-drawing, printable)
|
||||||
|
0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F,0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567, //0xc0(box-drawing, printable)
|
||||||
|
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B,0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580, //0xd0(box-drawing, printable)
|
||||||
|
0x03B1,0x00DF,0x0393,0x03C0,0x03A3,0x03C3,0x00B5,0x03C4,0x03A6,0x0398,0x03A9,0x03B4,0x221E,0x03C6,0x03B5,0x2229, //0xe0(maths(greek), printable)
|
||||||
|
0x2261,0x00B1,0x2265,0x2264,0x2320,0x2321,0x00F7,0x2248,0x00B0,0x2219,0x00B7,0x221A,0x207F,0x00B2,0x25A0,0x00A0, //0xf0(maths, printable)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static qboolean FSZIP_FindEndCentralDirectory(zipfile_t *zip, struct zipinfo *info)
|
||||||
|
{
|
||||||
|
qboolean result = false;
|
||||||
|
//zip comment is capped to 65k or so, so we can use a single buffer for this
|
||||||
|
byte traildata[0x10000 + SIZE_ENDOFCENTRALDIRECTORY+SIZE_ZIP64ENDOFCENTRALDIRECTORYLOCATOR];
|
||||||
|
byte *magic;
|
||||||
|
unsigned int trailsize = 0x10000 + SIZE_ENDOFCENTRALDIRECTORY+SIZE_ZIP64ENDOFCENTRALDIRECTORYLOCATOR;
|
||||||
|
if ((qofs_t)trailsize > zip->rawsize)
|
||||||
|
trailsize = zip->rawsize;
|
||||||
|
//FIXME: do in a loop to avoid a huge block of stack use
|
||||||
|
Sys_FileSeek(zip->raw, zip->rawsize - trailsize);
|
||||||
|
Sys_FileRead(zip->raw, traildata, trailsize);
|
||||||
|
|
||||||
|
memset(info, 0, sizeof(*info));
|
||||||
|
|
||||||
|
for (magic = traildata+trailsize-SIZE_ENDOFCENTRALDIRECTORY; magic >= traildata; magic--)
|
||||||
|
{
|
||||||
|
if (magic[0] == 'P' &&
|
||||||
|
magic[1] == 'K' &&
|
||||||
|
magic[2] == 5 &&
|
||||||
|
magic[3] == 6)
|
||||||
|
{
|
||||||
|
info->centraldir_end = (zip->rawsize-trailsize)+(magic-traildata);
|
||||||
|
|
||||||
|
info->thisdisk = LittleU2FromPtr(magic+4);
|
||||||
|
info->centraldir_startdisk = LittleU2FromPtr(magic+6);
|
||||||
|
info->centraldir_numfiles_disk = LittleU2FromPtr(magic+8);
|
||||||
|
info->centraldir_numfiles_all = LittleU2FromPtr(magic+10);
|
||||||
|
info->centraldir_size = LittleU4FromPtr(magic+12);
|
||||||
|
info->centraldir_offset = LittleU4FromPtr(magic+16);
|
||||||
|
info->commentlength = LittleU2FromPtr(magic+20);
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
Con_Printf("zip: unable to find end-of-central-directory\n");
|
||||||
|
else
|
||||||
|
|
||||||
|
//now look for a zip64 header.
|
||||||
|
//this gives more larger archives, more files, larger files, more spanned disks.
|
||||||
|
//note that the central directory itself is the same, it just has a couple of extra attributes on files that need them.
|
||||||
|
for (magic -= SIZE_ZIP64ENDOFCENTRALDIRECTORYLOCATOR; magic >= traildata; magic--)
|
||||||
|
{
|
||||||
|
if (magic[0] == 'P' &&
|
||||||
|
magic[1] == 'K' &&
|
||||||
|
magic[2] == 6 &&
|
||||||
|
magic[3] == 7)
|
||||||
|
{
|
||||||
|
byte z64eocd[SIZE_ZIP64ENDOFCENTRALDIRECTORY];
|
||||||
|
|
||||||
|
info->zip64_centraldirend_disk = LittleU4FromPtr(magic+4);
|
||||||
|
info->zip64_centraldirend_offset = LittleU8FromPtr(magic+8);
|
||||||
|
info->zip64_diskcount = LittleU4FromPtr(magic+16);
|
||||||
|
|
||||||
|
if (info->zip64_diskcount != 1 || info->zip64_centraldirend_disk != 0)
|
||||||
|
{
|
||||||
|
Con_Printf("zip: archive is spanned\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sys_FileSeek(zip->raw, info->zip64_centraldirend_offset);
|
||||||
|
Sys_FileRead(zip->raw, z64eocd, sizeof(z64eocd));
|
||||||
|
|
||||||
|
if (z64eocd[0] == 'P' &&
|
||||||
|
z64eocd[1] == 'K' &&
|
||||||
|
z64eocd[2] == 6 &&
|
||||||
|
z64eocd[3] == 6)
|
||||||
|
{
|
||||||
|
info->zip64_eocdsize = LittleU8FromPtr(z64eocd+4) + 12;
|
||||||
|
info->zip64_version_madeby = LittleU2FromPtr(z64eocd+12);
|
||||||
|
info->zip64_version_needed = LittleU2FromPtr(z64eocd+14);
|
||||||
|
info->thisdisk = LittleU4FromPtr(z64eocd+16);
|
||||||
|
info->centraldir_startdisk = LittleU4FromPtr(z64eocd+20);
|
||||||
|
info->centraldir_numfiles_disk = LittleU8FromPtr(z64eocd+24);
|
||||||
|
info->centraldir_numfiles_all = LittleU8FromPtr(z64eocd+32);
|
||||||
|
info->centraldir_size = LittleU8FromPtr(z64eocd+40);
|
||||||
|
info->centraldir_offset = LittleU8FromPtr(z64eocd+48);
|
||||||
|
|
||||||
|
if (info->zip64_eocdsize >= 84)
|
||||||
|
{
|
||||||
|
info->centraldir_compressionmethod = LittleU2FromPtr(z64eocd+56);
|
||||||
|
// info->zip64_2_centraldir_csize = LittleU8FromPtr(z64eocd+58);
|
||||||
|
// info->zip64_2_centraldir_usize = LittleU8FromPtr(z64eocd+66);
|
||||||
|
info->centraldir_algid = LittleU2FromPtr(z64eocd+74);
|
||||||
|
// info.zip64_2_bitlen = LittleU2FromPtr(z64eocd+76);
|
||||||
|
// info->zip64_2_flags = LittleU2FromPtr(z64eocd+78);
|
||||||
|
// info->zip64_2_hashid = LittleU2FromPtr(z64eocd+80);
|
||||||
|
// info->zip64_2_hashlength = LittleU2FromPtr(z64eocd+82);
|
||||||
|
//info->zip64_2_hashdata = LittleUXFromPtr(z64eocd+84, info->zip64_2_hashlength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf("zip: zip64 end-of-central directory at unknown offset.\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->thisdisk || info->centraldir_startdisk || info->centraldir_numfiles_disk != info->centraldir_numfiles_all)
|
||||||
|
{
|
||||||
|
Con_Printf("zip: archive is spanned\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
if (info->centraldir_compressionmethod || info->centraldir_algid)
|
||||||
|
{
|
||||||
|
Con_Printf("zip: encrypted centraldir\n");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, byte *data, struct zipcentralentry *entry)
|
||||||
|
{
|
||||||
|
entry->flags = 0;
|
||||||
|
entry->fname = (unsigned char*)"";
|
||||||
|
entry->fnane_len = 0;
|
||||||
|
|
||||||
|
if (data[0] != 'P' ||
|
||||||
|
data[1] != 'K' ||
|
||||||
|
data[2] != 1 ||
|
||||||
|
data[3] != 2)
|
||||||
|
return false; //verify the signature
|
||||||
|
|
||||||
|
//if we read too much, we'll catch it after.
|
||||||
|
entry->version_madeby = LittleU2FromPtr(data+4);
|
||||||
|
entry->version_needed = LittleU2FromPtr(data+6);
|
||||||
|
entry->gflags = LittleU2FromPtr(data+8);
|
||||||
|
entry->cmethod = LittleU2FromPtr(data+10);
|
||||||
|
entry->lastmodfiletime = LittleU2FromPtr(data+12);
|
||||||
|
entry->lastmodfiledate = LittleU2FromPtr(data+12);
|
||||||
|
entry->crc32 = LittleU4FromPtr(data+16);
|
||||||
|
entry->csize = LittleU4FromPtr(data+20);
|
||||||
|
entry->usize = LittleU4FromPtr(data+24);
|
||||||
|
entry->fnane_len = LittleU2FromPtr(data+28);
|
||||||
|
entry->extra_len = LittleU2FromPtr(data+30);
|
||||||
|
entry->comment_len = LittleU2FromPtr(data+32);
|
||||||
|
entry->disknum = LittleU2FromPtr(data+34);
|
||||||
|
entry->iattributes = LittleU2FromPtr(data+36);
|
||||||
|
entry->eattributes = LittleU4FromPtr(data+38);
|
||||||
|
entry->localheaderoffset = LittleU4FromPtr(data+42);
|
||||||
|
entry->cesize = 46;
|
||||||
|
|
||||||
|
//mark the filename position
|
||||||
|
entry->fname = data+entry->cesize;
|
||||||
|
entry->cesize += entry->fnane_len;
|
||||||
|
|
||||||
|
entry->mtime = 0;
|
||||||
|
|
||||||
|
//parse extra
|
||||||
|
if (entry->extra_len)
|
||||||
|
{
|
||||||
|
byte *extra = data + entry->cesize;
|
||||||
|
byte *extraend = extra + entry->extra_len;
|
||||||
|
unsigned short extrachunk_tag;
|
||||||
|
unsigned short extrachunk_len;
|
||||||
|
while(extra+4 < extraend)
|
||||||
|
{
|
||||||
|
extrachunk_tag = LittleU2FromPtr(extra+0);
|
||||||
|
extrachunk_len = LittleU2FromPtr(extra+2);
|
||||||
|
if (extra + extrachunk_len > extraend)
|
||||||
|
break; //error
|
||||||
|
extra += 4;
|
||||||
|
|
||||||
|
switch(extrachunk_tag)
|
||||||
|
{
|
||||||
|
case 1: //zip64 extended information extra field. the attributes are only present if the reegular file info is nulled out with a -1
|
||||||
|
if (entry->usize == 0xffffffffu)
|
||||||
|
{
|
||||||
|
entry->usize = LittleU8FromPtr(extra);
|
||||||
|
extra += 8;
|
||||||
|
}
|
||||||
|
if (entry->csize == 0xffffffffu)
|
||||||
|
{
|
||||||
|
entry->csize = LittleU8FromPtr(extra);
|
||||||
|
extra += 8;
|
||||||
|
}
|
||||||
|
if (entry->localheaderoffset == 0xffffffffu)
|
||||||
|
{
|
||||||
|
entry->localheaderoffset = LittleU8FromPtr(extra);
|
||||||
|
extra += 8;
|
||||||
|
}
|
||||||
|
if (entry->disknum == 0xffffu)
|
||||||
|
{
|
||||||
|
entry->disknum = LittleU4FromPtr(extra);
|
||||||
|
extra += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER > 1200
|
||||||
|
case 0x000a: //NTFS extra field
|
||||||
|
//0+4: reserved
|
||||||
|
//4+2: subtag(must be 1, for times)
|
||||||
|
//6+2: subtagsize(times: must be == 8*3+4)
|
||||||
|
//8+8: mtime
|
||||||
|
//16+8: atime
|
||||||
|
//24+8: ctime
|
||||||
|
if (extrachunk_len >= 32 && LittleU2FromPtr(extra+4) == 1 && LittleU2FromPtr(extra+6) == 8*3)
|
||||||
|
entry->mtime = LittleU8FromPtr(extra+8) / 10000000ULL - 11644473600ULL;
|
||||||
|
else
|
||||||
|
Con_Printf("zip: unsupported ntfs subchunk %x\n", extrachunk_tag);
|
||||||
|
extra += extrachunk_len;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 0x5455:
|
||||||
|
if (extra[0] & 1)
|
||||||
|
entry->mtime = LittleU4FromPtr(extra+1);
|
||||||
|
//access and creation do NOT exist in the central header.
|
||||||
|
extra += extrachunk_len;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Con_Printf("Unknown chunk %x\n", extrachunk_tag);
|
||||||
|
case 0x5455: //extended timestamp
|
||||||
|
case 0x7875: //unix uid/gid
|
||||||
|
case 0x9901: //aes crypto
|
||||||
|
*/ extra += extrachunk_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry->cesize += entry->extra_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
//parse comment
|
||||||
|
entry->cesize += entry->comment_len;
|
||||||
|
|
||||||
|
//check symlink flags
|
||||||
|
{
|
||||||
|
byte madeby = entry->version_madeby>>8; //system
|
||||||
|
//vms, unix, or beos file attributes includes a symlink attribute.
|
||||||
|
//symlinks mean the file contents is just the name of another file.
|
||||||
|
if (madeby == 2 || madeby == 3 || madeby == 16)
|
||||||
|
{
|
||||||
|
unsigned short unixattr = entry->eattributes>>16;
|
||||||
|
if ((unixattr & 0xF000) == 0xA000)//fa&S_IFMT==S_IFLNK
|
||||||
|
entry->flags |= ZFL_SYMLINK;
|
||||||
|
else if ((unixattr & 0xA000) == 0xA000)//fa&S_IFMT==S_IFLNK
|
||||||
|
entry->flags |= ZFL_SYMLINK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->gflags & (1u<<0)) //encrypted
|
||||||
|
{
|
||||||
|
#ifdef ZIPCRYPT
|
||||||
|
entry->flags |= ZFL_WEAKENCRYPT;
|
||||||
|
#else
|
||||||
|
entry->flags |= ZFL_CORRUPT;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (entry->gflags & (1u<<5)) //is patch data
|
||||||
|
entry->flags |= ZFL_CORRUPT;
|
||||||
|
else if (entry->gflags & (1u<<6)) //strong encryption
|
||||||
|
entry->flags |= ZFL_CORRUPT;
|
||||||
|
else if (entry->gflags & (1u<<13)) //strong encryption
|
||||||
|
entry->flags |= ZFL_CORRUPT;
|
||||||
|
else if (entry->cmethod == 0)
|
||||||
|
entry->flags |= ZFL_STORED;
|
||||||
|
//1: shrink
|
||||||
|
//2-5: reduce
|
||||||
|
//6: implode
|
||||||
|
//7: tokenize
|
||||||
|
else if (entry->cmethod == 8)
|
||||||
|
entry->flags |= ZFL_DEFLATED;
|
||||||
|
//8: deflate64 - patented. sometimes written by microsoft's crap, so this might be problematic. only minor improvements.
|
||||||
|
//10: implode
|
||||||
|
//12: bzip2
|
||||||
|
// else if (entry->cmethod == 12)
|
||||||
|
// entry->flags |= ZFL_BZIP2;
|
||||||
|
// else if (entry->cmethod == 14)
|
||||||
|
// entry->flags |= ZFL_LZMA;
|
||||||
|
//19: lz77
|
||||||
|
//97: wavpack
|
||||||
|
//98: ppmd
|
||||||
|
else
|
||||||
|
entry->flags |= ZFL_CORRUPT; //unsupported compression method.
|
||||||
|
|
||||||
|
if ((entry->flags & ZFL_WEAKENCRYPT) && !(entry->flags & ZFL_DEFLATED))
|
||||||
|
entry->flags |= ZFL_CORRUPT; //only support decryption with deflate.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean FSZIP_EnumerateCentralDirectory(zipfile_t *zip, struct zipinfo *info, const char *prefix)
|
||||||
|
{
|
||||||
|
qboolean success = false;
|
||||||
|
zpackfile_t *f;
|
||||||
|
struct zipcentralentry entry;
|
||||||
|
qofs_t ofs = 0;
|
||||||
|
unsigned int i;
|
||||||
|
//lazily read the entire thing.
|
||||||
|
byte *centraldir = malloc(info->centraldir_size);
|
||||||
|
if (centraldir)
|
||||||
|
{
|
||||||
|
Sys_FileSeek(zip->raw, info->centraldir_offset+info->zipoffset);
|
||||||
|
if ((qofs_t)Sys_FileRead(zip->raw, centraldir, info->centraldir_size) == info->centraldir_size)
|
||||||
|
{
|
||||||
|
zip->numfiles = info->centraldir_numfiles_disk;
|
||||||
|
zip->files = f = Z_Malloc (zip->numfiles * sizeof(*f));
|
||||||
|
|
||||||
|
for (i = 0; i < zip->numfiles; i++)
|
||||||
|
{
|
||||||
|
if (!FSZIP_ReadCentralEntry(zip, centraldir+ofs, &entry) || ofs + entry.cesize > info->centraldir_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
f->crc = entry.crc32;
|
||||||
|
|
||||||
|
//copy out the filename and lowercase it
|
||||||
|
if (entry.gflags & (1u<<11))
|
||||||
|
{ //already utf-8 encoding
|
||||||
|
if (entry.fnane_len > sizeof(f->name)-1)
|
||||||
|
entry.fnane_len = sizeof(f->name)-1;
|
||||||
|
memcpy(f->name, entry.fname, entry.fnane_len);
|
||||||
|
f->name[entry.fnane_len] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //legacy charset
|
||||||
|
int i;
|
||||||
|
int nlen = 0;
|
||||||
|
int cl;
|
||||||
|
for (i = 0; i < entry.fnane_len; i++)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
cl = ibmtounicode[entry.fname[i]];
|
||||||
|
if (cl > 127)
|
||||||
|
f->name[nlen] = '?'; //we can't encode non-ascii chars
|
||||||
|
else
|
||||||
|
f->name[nlen] = cl;
|
||||||
|
cl = 1;
|
||||||
|
#else
|
||||||
|
cl = utf8_encode(f->name+nlen, ibmtounicode[entry.fname[i]], sizeof(f->name)-1 - nlen);
|
||||||
|
#endif
|
||||||
|
if (!cl) //overflowed, truncate cleanly.
|
||||||
|
break;
|
||||||
|
nlen += cl;
|
||||||
|
}
|
||||||
|
f->name[nlen] = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefix && *prefix)
|
||||||
|
{
|
||||||
|
if (!strcmp(prefix, ".."))
|
||||||
|
{
|
||||||
|
char *c;
|
||||||
|
for (c = f->name; *c; )
|
||||||
|
{
|
||||||
|
if (*c++ == '/')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memmove(f->name, c, strlen(c)+1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t prelen = strlen(prefix);
|
||||||
|
size_t oldlen = strlen(f->name);
|
||||||
|
if (prelen+1+oldlen+1 > sizeof(f->name))
|
||||||
|
*f->name = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memmove(f->name+prelen+1, f->name, oldlen);
|
||||||
|
f->name[prelen] = '/';
|
||||||
|
memmove(f->name, prefix, prelen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q_strlwr(f->name);
|
||||||
|
|
||||||
|
f->filelen = *f->name?entry.usize:0;
|
||||||
|
f->localpos = entry.localheaderoffset+info->zipoffset;
|
||||||
|
f->flags = entry.flags;
|
||||||
|
// f->mtime = entry.mtime;
|
||||||
|
|
||||||
|
ofs += entry.cesize;
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
|
||||||
|
success = i == zip->numfiles;
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
free(zip->files);
|
||||||
|
zip->files = NULL;
|
||||||
|
zip->numfiles = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(centraldir);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qofs_t *datastart, qofs_t *datasize)
|
||||||
|
{
|
||||||
|
struct ziplocalentry local;
|
||||||
|
byte localdata[SIZE_LOCALENTRY];
|
||||||
|
qofs_t localstart = zfile->localpos;
|
||||||
|
|
||||||
|
Sys_FileSeek(zip->raw, localstart);
|
||||||
|
Sys_FileRead(zip->raw, localdata, sizeof(localdata));
|
||||||
|
|
||||||
|
//make sure we found the right sort of table.
|
||||||
|
if (localdata[0] != 'P' ||
|
||||||
|
localdata[1] != 'K' ||
|
||||||
|
localdata[2] != 3 ||
|
||||||
|
localdata[3] != 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
local.version_needed = LittleU2FromPtr(localdata+4);
|
||||||
|
local.gpflags = LittleU2FromPtr(localdata+6);
|
||||||
|
local.cmethod = LittleU2FromPtr(localdata+8);
|
||||||
|
local.lastmodfiletime = LittleU2FromPtr(localdata+10);
|
||||||
|
local.lastmodfiledate = LittleU2FromPtr(localdata+12);
|
||||||
|
local.crc32 = LittleU4FromPtr(localdata+14);
|
||||||
|
local.csize = LittleU4FromPtr(localdata+18);
|
||||||
|
local.usize = LittleU4FromPtr(localdata+22);
|
||||||
|
local.fname_len = LittleU2FromPtr(localdata+26);
|
||||||
|
local.extra_len = LittleU2FromPtr(localdata+28);
|
||||||
|
|
||||||
|
localstart += SIZE_LOCALENTRY;
|
||||||
|
localstart += local.fname_len;
|
||||||
|
|
||||||
|
//parse extra
|
||||||
|
if (local.usize == 0xffffffffu || local.csize == 0xffffffffu) //don't bother otherwise.
|
||||||
|
if (local.extra_len)
|
||||||
|
{
|
||||||
|
byte extradata[65536];
|
||||||
|
byte *extra = extradata;
|
||||||
|
byte *extraend = extradata + local.extra_len;
|
||||||
|
unsigned short extrachunk_tag;
|
||||||
|
unsigned short extrachunk_len;
|
||||||
|
|
||||||
|
Sys_FileSeek(zip->raw, localstart);
|
||||||
|
Sys_FileRead(zip->raw, extradata, sizeof(extradata));
|
||||||
|
|
||||||
|
while(extra+4 < extraend)
|
||||||
|
{
|
||||||
|
extrachunk_tag = LittleU2FromPtr(extra+0);
|
||||||
|
extrachunk_len = LittleU2FromPtr(extra+2);
|
||||||
|
if (extra + extrachunk_len > extraend)
|
||||||
|
break; //error
|
||||||
|
extra += 4;
|
||||||
|
|
||||||
|
switch(extrachunk_tag)
|
||||||
|
{
|
||||||
|
case 1: //zip64 extended information extra field. the attributes are only present if the reegular file info is nulled out with a -1
|
||||||
|
if (local.usize == 0xffffffffu)
|
||||||
|
{
|
||||||
|
local.usize = LittleU8FromPtr(extra);
|
||||||
|
extra += 8;
|
||||||
|
}
|
||||||
|
if (local.csize == 0xffffffffu)
|
||||||
|
{
|
||||||
|
local.csize = LittleU8FromPtr(extra);
|
||||||
|
extra += 8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Con_Printf("Unknown chunk %x\n", extrachunk_tag);
|
||||||
|
case 0x000a: //NTFS (timestamps)
|
||||||
|
case 0x5455: //extended timestamp
|
||||||
|
case 0x7875: //unix uid/gid
|
||||||
|
*/ extra += extrachunk_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localstart += local.extra_len;
|
||||||
|
*datastart = localstart; //this is the end of the local block, and the start of the data block (well, actually, should be encryption, but we don't support that).
|
||||||
|
*datasize = local.csize;
|
||||||
|
|
||||||
|
if (local.gpflags & (1u<<3))
|
||||||
|
{
|
||||||
|
//crc, usize, and csize were not known at the time the file was compressed.
|
||||||
|
//there is a 'data descriptor' after the file data, but to parse that we would need to decompress the file.
|
||||||
|
//instead, just depend upon upon the central directory and don't bother checking.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (local.crc32 != zfile->crc)
|
||||||
|
return false;
|
||||||
|
if (local.usize != zfile->filelen)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: with pure paths, we still don't bother checking the crc (again, would require decompressing the entire file in advance).
|
||||||
|
|
||||||
|
if (local.cmethod == 0)
|
||||||
|
return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED)) == ZFL_STORED;
|
||||||
|
if (local.cmethod == 8)
|
||||||
|
return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED)) == ZFL_DEFLATED;
|
||||||
|
return false; //some other method that we don't know.
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_t *FSZIP_LoadArchive (const char *packfile)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
packfile_t *newfiles;
|
||||||
|
int numpackfiles;
|
||||||
|
pack_t *pack;
|
||||||
|
|
||||||
|
zipfile_t zip;
|
||||||
|
struct zipinfo info;
|
||||||
|
|
||||||
|
#ifndef USE_ZLIB
|
||||||
|
qboolean zlibneeded = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
zip.rawsize = Sys_FileOpenRead(packfile, &zip.raw);
|
||||||
|
if (zip.raw < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//try to find the header
|
||||||
|
if (!FSZIP_FindEndCentralDirectory(&zip, &info))
|
||||||
|
{
|
||||||
|
Sys_FileClose(zip.raw);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//now try to read it.
|
||||||
|
if (!FSZIP_EnumerateCentralDirectory(&zip, &info, "") && !info.zip64_diskcount)
|
||||||
|
{
|
||||||
|
//uh oh... the central directory wasn't where it was meant to be!
|
||||||
|
//assuming that the endofcentraldir is packed at the true end of the centraldir (and that we're not zip64 and thus don't have an extra block), then we can guess based upon the offset difference
|
||||||
|
info.zipoffset = info.centraldir_end - (info.centraldir_offset+info.centraldir_size);
|
||||||
|
if (!FSZIP_EnumerateCentralDirectory(&zip, &info, ""))
|
||||||
|
{
|
||||||
|
Sys_FileClose(zip.raw);
|
||||||
|
Con_Printf ("zipfile \"%s\" appears to be missing its central directory\n", packfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//lame zone.
|
||||||
|
//copy the files into something compatible with quake's pak support.
|
||||||
|
//ignore compressed / corrupt / unusable files
|
||||||
|
pack = (pack_t *) Z_Malloc (sizeof (pack_t));
|
||||||
|
q_strlcpy (pack->filename, packfile, sizeof(pack->filename));
|
||||||
|
pack->handle = zip.raw;
|
||||||
|
|
||||||
|
numpackfiles = 0;
|
||||||
|
newfiles = NULL;
|
||||||
|
|
||||||
|
newfiles = Z_Malloc(sizeof(*newfiles) * zip.numfiles);
|
||||||
|
for (numpackfiles = 0, i = 0; i < zip.numfiles; i++)
|
||||||
|
{
|
||||||
|
qofs_t startpos, datasize;
|
||||||
|
zpackfile_t *zp = &zip.files[i];
|
||||||
|
if (zp->flags & ZFL_CORRUPT)
|
||||||
|
continue; //we can't cope with this.
|
||||||
|
if (zp->flags & ZFL_SYMLINK)
|
||||||
|
continue; //file data is just a filename
|
||||||
|
|
||||||
|
if (!FSZIP_ValidateLocalHeader(&zip, zp, &startpos, &datasize))
|
||||||
|
continue; //local header is corrupt
|
||||||
|
|
||||||
|
if (zp->flags & ZFL_DEFLATED)
|
||||||
|
{
|
||||||
|
#ifndef USE_ZLIB
|
||||||
|
zlibneeded = true;
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (zp->flags & ZFL_STORED)
|
||||||
|
{
|
||||||
|
if (datasize != zp->filelen)
|
||||||
|
continue;
|
||||||
|
datasize = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//usable file.
|
||||||
|
memcpy(newfiles[numpackfiles].name, zp->name, MAX_QPATH-1);
|
||||||
|
newfiles[numpackfiles].name[MAX_QPATH-1] = 0;
|
||||||
|
newfiles[numpackfiles].filelen = zp->filelen;
|
||||||
|
newfiles[numpackfiles].filepos = startpos;
|
||||||
|
newfiles[numpackfiles].deflatedsize = datasize;
|
||||||
|
numpackfiles++;
|
||||||
|
}
|
||||||
|
pack->numfiles = numpackfiles;
|
||||||
|
pack->files = newfiles;
|
||||||
|
|
||||||
|
//we don't need this stuff now.
|
||||||
|
Z_Free(zip.files);
|
||||||
|
|
||||||
|
#ifndef USE_ZLIB
|
||||||
|
if (zlibneeded)
|
||||||
|
Con_Printf ("zipfile \"%s\" contains compressed files, but zlib was disabled at compile time.\n", packfile);
|
||||||
|
#endif
|
||||||
|
//Sys_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
|
||||||
|
return pack;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *FSZIP_Deflate(FILE *src, int srcsize, int outsize)
|
||||||
|
{
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
byte inbuffer[65536];
|
||||||
|
byte outbuffer[65536];
|
||||||
|
z_stream strm;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
FILE *of;
|
||||||
|
#ifdef _WIN32
|
||||||
|
/*warning: annother app might manage to open the file before we can. if the file is not opened exclusively then we can end up with issues
|
||||||
|
on windows, fopen is typically exclusive anyway, but not on unix. but on unix, tmpfile is actually usable, so special-case the windows code and hope that its never an issue
|
||||||
|
tmpfile isn't usable in windows. it creates the file in the root dir and requires admin rights, which is stupid.
|
||||||
|
*/
|
||||||
|
char *fname = _tempnam(NULL, "ftemp");
|
||||||
|
of = fopen(fname, "w+bD");
|
||||||
|
#else
|
||||||
|
of = tmpfile();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!of)
|
||||||
|
{
|
||||||
|
fclose(src);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&strm, 0, sizeof(strm));
|
||||||
|
strm.data_type = Z_UNKNOWN;
|
||||||
|
inflateInit2(&strm, -MAX_WBITS);
|
||||||
|
while ((ret=inflate(&strm, Z_SYNC_FLUSH)) != Z_STREAM_END)
|
||||||
|
{
|
||||||
|
if (strm.avail_in == 0 || strm.avail_out == 0)
|
||||||
|
{
|
||||||
|
if (strm.avail_in == 0)
|
||||||
|
{
|
||||||
|
strm.avail_in = fread(inbuffer, 1, sizeof(inbuffer), src);
|
||||||
|
strm.next_in = inbuffer;
|
||||||
|
if (!strm.avail_in)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strm.avail_out == 0)
|
||||||
|
{
|
||||||
|
strm.next_out = outbuffer;
|
||||||
|
fwrite(outbuffer, 1, strm.total_out, of);
|
||||||
|
strm.total_out = 0;
|
||||||
|
strm.avail_out = sizeof(outbuffer);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//doh, it terminated for no reason
|
||||||
|
if (ret != Z_STREAM_END)
|
||||||
|
{
|
||||||
|
inflateEnd(&strm);
|
||||||
|
fclose(src);
|
||||||
|
fclose(of);
|
||||||
|
Con_Printf("Couldn't decompress file\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fwrite(outbuffer, 1, strm.total_out, of);
|
||||||
|
inflateEnd(&strm);
|
||||||
|
|
||||||
|
fclose(src);
|
||||||
|
|
||||||
|
fseek(of, SEEK_SET, 0);
|
||||||
|
return of;
|
||||||
|
#else
|
||||||
|
fclose(src);
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
//extern unsigned char d_15to8table[65536]; //johnfitz -- never used
|
//extern unsigned char d_15to8table[65536]; //johnfitz -- never used
|
||||||
|
|
||||||
|
qboolean premul_hud = false;//true;
|
||||||
cvar_t scr_conalpha = {"scr_conalpha", "0.5", CVAR_ARCHIVE}; //johnfitz
|
cvar_t scr_conalpha = {"scr_conalpha", "0.5", CVAR_ARCHIVE}; //johnfitz
|
||||||
|
|
||||||
qpic_t *draw_disc;
|
qpic_t *draw_disc;
|
||||||
|
@ -202,7 +203,7 @@ void Scrap_Upload (void)
|
||||||
{
|
{
|
||||||
sprintf (name, "scrap%i", i);
|
sprintf (name, "scrap%i", i);
|
||||||
scrap_textures[i] = TexMgr_LoadImage (NULL, name, BLOCK_WIDTH, BLOCK_HEIGHT, SRC_INDEXED, scrap_texels[i],
|
scrap_textures[i] = TexMgr_LoadImage (NULL, name, BLOCK_WIDTH, BLOCK_HEIGHT, SRC_INDEXED, scrap_texels[i],
|
||||||
"", (src_offset_t)scrap_texels[i], TEXPREF_ALPHA | TEXPREF_OVERWRITE | TEXPREF_NOPICMIP);
|
"", (src_offset_t)scrap_texels[i], (premul_hud?TEXPREF_PREMULTIPLY:0)|TEXPREF_ALPHA | TEXPREF_OVERWRITE | TEXPREF_NOPICMIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
scrap_dirty = false;
|
scrap_dirty = false;
|
||||||
|
@ -252,7 +253,7 @@ qpic_t *Draw_PicFromWad (const char *name)
|
||||||
offset = (src_offset_t)p - (src_offset_t)wad_base + sizeof(int)*2; //johnfitz
|
offset = (src_offset_t)p - (src_offset_t)wad_base + sizeof(int)*2; //johnfitz
|
||||||
|
|
||||||
gl.gltexture = TexMgr_LoadImage (NULL, texturename, p->width, p->height, SRC_INDEXED, p->data, WADFILENAME,
|
gl.gltexture = TexMgr_LoadImage (NULL, texturename, p->width, p->height, SRC_INDEXED, p->data, WADFILENAME,
|
||||||
offset, TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr
|
offset, (premul_hud?TEXPREF_PREMULTIPLY:0)|TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr
|
||||||
gl.sl = 0;
|
gl.sl = 0;
|
||||||
gl.sh = (float)p->width/(float)TexMgr_PadConditional(p->width); //johnfitz
|
gl.sh = (float)p->width/(float)TexMgr_PadConditional(p->width); //johnfitz
|
||||||
gl.tl = 0;
|
gl.tl = 0;
|
||||||
|
@ -304,7 +305,7 @@ qpic_t *Draw_CachePic (const char *path)
|
||||||
pic->pic.height = dat->height;
|
pic->pic.height = dat->height;
|
||||||
|
|
||||||
gl.gltexture = TexMgr_LoadImage (NULL, path, dat->width, dat->height, SRC_INDEXED, dat->data, path,
|
gl.gltexture = TexMgr_LoadImage (NULL, path, dat->width, dat->height, SRC_INDEXED, dat->data, path,
|
||||||
sizeof(int)*2, TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr
|
sizeof(int)*2, (premul_hud?TEXPREF_PREMULTIPLY:0)|TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr
|
||||||
gl.sl = 0;
|
gl.sl = 0;
|
||||||
gl.sh = (float)dat->width/(float)TexMgr_PadConditional(dat->width); //johnfitz
|
gl.sh = (float)dat->width/(float)TexMgr_PadConditional(dat->width); //johnfitz
|
||||||
gl.tl = 0;
|
gl.tl = 0;
|
||||||
|
@ -359,7 +360,7 @@ void Draw_LoadPics (void)
|
||||||
if (!data) Sys_Error ("Draw_LoadPics: couldn't load conchars");
|
if (!data) Sys_Error ("Draw_LoadPics: couldn't load conchars");
|
||||||
offset = (src_offset_t)data - (src_offset_t)wad_base;
|
offset = (src_offset_t)data - (src_offset_t)wad_base;
|
||||||
char_texture = TexMgr_LoadImage (NULL, WADFILENAME":conchars", 128, 128, SRC_INDEXED, data,
|
char_texture = TexMgr_LoadImage (NULL, WADFILENAME":conchars", 128, 128, SRC_INDEXED, data,
|
||||||
WADFILENAME, offset, TEXPREF_ALPHA | TEXPREF_NEAREST | TEXPREF_NOPICMIP | TEXPREF_CONCHARS);
|
WADFILENAME, offset, (premul_hud?TEXPREF_PREMULTIPLY:0)|TEXPREF_ALPHA | TEXPREF_NEAREST | TEXPREF_NOPICMIP | TEXPREF_CONCHARS);
|
||||||
|
|
||||||
draw_disc = Draw_PicFromWad ("disc");
|
draw_disc = Draw_PicFromWad ("disc");
|
||||||
draw_backtile = Draw_PicFromWad ("backtile");
|
draw_backtile = Draw_PicFromWad ("backtile");
|
||||||
|
@ -567,19 +568,28 @@ void Draw_ConsoleBackground (void)
|
||||||
{
|
{
|
||||||
if (alpha < 1.0)
|
if (alpha < 1.0)
|
||||||
{
|
{
|
||||||
glEnable (GL_BLEND);
|
if (premul_hud)
|
||||||
glColor4f (1,1,1,alpha);
|
glColor4f (alpha,alpha,alpha,alpha);
|
||||||
glDisable (GL_ALPHA_TEST);
|
else
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
{
|
||||||
|
glEnable (GL_BLEND);
|
||||||
|
glDisable (GL_ALPHA_TEST);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
|
||||||
|
glColor4f (1,1,1,alpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw_Pic (0, 0, pic);
|
Draw_Pic (0, 0, pic);
|
||||||
|
|
||||||
if (alpha < 1.0)
|
if (alpha < 1.0)
|
||||||
{
|
{
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
if (!premul_hud)
|
||||||
glEnable (GL_ALPHA_TEST);
|
{
|
||||||
glDisable (GL_BLEND);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
glEnable (GL_ALPHA_TEST);
|
||||||
|
glDisable (GL_BLEND);
|
||||||
|
}
|
||||||
glColor4f (1,1,1,1);
|
glColor4f (1,1,1,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -766,7 +776,17 @@ void GL_Set2D (void)
|
||||||
|
|
||||||
glDisable (GL_DEPTH_TEST);
|
glDisable (GL_DEPTH_TEST);
|
||||||
glDisable (GL_CULL_FACE);
|
glDisable (GL_CULL_FACE);
|
||||||
glDisable (GL_BLEND);
|
|
||||||
glEnable (GL_ALPHA_TEST);
|
if (premul_hud)
|
||||||
|
{
|
||||||
|
glEnable (GL_BLEND);
|
||||||
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glDisable (GL_BLEND);
|
||||||
|
glEnable (GL_ALPHA_TEST);
|
||||||
|
}
|
||||||
glColor4f (1,1,1,1);
|
glColor4f (1,1,1,1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,6 +375,23 @@ void Fog_NewMap (void)
|
||||||
Fog_MarkModels (); //for volumetric fog
|
Fog_MarkModels (); //for volumetric fog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
Fog_NewMap
|
||||||
|
|
||||||
|
so fog is preserved when starting a demo recording
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
const char *Fog_GetFogCommand(void)
|
||||||
|
{
|
||||||
|
if (fade_done)
|
||||||
|
{ //if this mod is using dynamic fog, make sure we start with the right values.
|
||||||
|
//don't bother with this if we got fog from a clientside worldspawn key.
|
||||||
|
return va("\nfog %g %g %g %g\n", fog_density, fog_red, fog_green, fog_blue);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
Fog_Init
|
Fog_Init
|
||||||
|
|
895
Quake/gl_mesh.c
895
Quake/gl_mesh.c
File diff suppressed because it is too large
Load Diff
671
Quake/gl_model.c
671
Quake/gl_model.c
File diff suppressed because it is too large
Load Diff
|
@ -33,14 +33,6 @@ m*_t structures are in-memory
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// entity effects
|
|
||||||
|
|
||||||
#define EF_BRIGHTFIELD 1
|
|
||||||
#define EF_MUZZLEFLASH 2
|
|
||||||
#define EF_BRIGHTLIGHT 4
|
|
||||||
#define EF_DIMLIGHT 8
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|
||||||
|
@ -95,7 +87,7 @@ typedef struct texture_s
|
||||||
int anim_min, anim_max; // time for this frame min <=time< max
|
int anim_min, anim_max; // time for this frame min <=time< max
|
||||||
struct texture_s *anim_next; // in the animation sequence
|
struct texture_s *anim_next; // in the animation sequence
|
||||||
struct texture_s *alternate_anims; // bmodels in frmae 1 use these
|
struct texture_s *alternate_anims; // bmodels in frmae 1 use these
|
||||||
unsigned offsets[MIPLEVELS]; // four mip maps stored
|
// unsigned offsets[MIPLEVELS]; // four mip maps stored
|
||||||
} texture_t;
|
} texture_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,11 +286,17 @@ typedef struct aliasmesh_s
|
||||||
unsigned short vertindex;
|
unsigned short vertindex;
|
||||||
} aliasmesh_t;
|
} aliasmesh_t;
|
||||||
|
|
||||||
typedef struct meshxyz_s
|
typedef struct meshxyz_mdl_s
|
||||||
{
|
{
|
||||||
byte xyz[4];
|
byte xyz[4];
|
||||||
signed char normal[4];
|
signed char normal[4];
|
||||||
} meshxyz_t;
|
} meshxyz_mdl_t;
|
||||||
|
|
||||||
|
typedef struct meshxyz_md3_s
|
||||||
|
{
|
||||||
|
signed short xyz[4];
|
||||||
|
signed char normal[4];
|
||||||
|
} meshxyz_md3_t;
|
||||||
|
|
||||||
typedef struct meshst_s
|
typedef struct meshst_s
|
||||||
{
|
{
|
||||||
|
@ -358,29 +356,37 @@ typedef struct {
|
||||||
|
|
||||||
//ericw -- used to populate vbo
|
//ericw -- used to populate vbo
|
||||||
int numverts_vbo; // number of verts with unique x,y,z,s,t
|
int numverts_vbo; // number of verts with unique x,y,z,s,t
|
||||||
intptr_t meshdesc; // offset into extradata: numverts_vbo aliasmesh_t
|
intptr_t meshdesc; // offset into extradata: numverts_vbo aliasmesh_t
|
||||||
int numindexes;
|
int numindexes;
|
||||||
intptr_t indexes; // offset into extradata: numindexes unsigned shorts
|
intptr_t indexes; // offset into extradata: numindexes unsigned shorts
|
||||||
intptr_t vertexes; // offset into extradata: numposes*vertsperframe trivertx_t
|
intptr_t vertexes; // offset into extradata: numposes*vertsperframe trivertx_t
|
||||||
|
|
||||||
|
intptr_t vbovertofs;
|
||||||
|
intptr_t vbostofs;
|
||||||
|
intptr_t eboofs;
|
||||||
//ericw --
|
//ericw --
|
||||||
|
|
||||||
|
intptr_t nextsurface; //spike
|
||||||
int numposes;
|
int numposes;
|
||||||
int poseverts;
|
int posevertssize; //spike 1=mdl, 2=md3
|
||||||
int posedata; // numposes*poseverts trivert_t
|
|
||||||
int commands; // gl command list with embedded s/t
|
|
||||||
struct gltexture_s *gltextures[MAX_SKINS][4]; //johnfitz
|
struct gltexture_s *gltextures[MAX_SKINS][4]; //johnfitz
|
||||||
struct gltexture_s *fbtextures[MAX_SKINS][4]; //johnfitz
|
struct gltexture_s *fbtextures[MAX_SKINS][4]; //johnfitz
|
||||||
int texels[MAX_SKINS]; // only for player skins
|
intptr_t texels[MAX_SKINS]; // only for player skins
|
||||||
maliasframedesc_t frames[1]; // variable sized
|
maliasframedesc_t frames[1]; // variable sized
|
||||||
} aliashdr_t;
|
} aliashdr_t;
|
||||||
|
|
||||||
#define MAXALIASVERTS 2000 //johnfitz -- was 1024
|
typedef struct {
|
||||||
#define MAXALIASFRAMES 256
|
short xyz[3];
|
||||||
#define MAXALIASTRIS 4096 //ericw -- was 2048
|
byte latlong[2];
|
||||||
extern aliashdr_t *pheader;
|
} md3XyzNormal_t;
|
||||||
extern stvert_t stverts[MAXALIASVERTS];
|
|
||||||
extern mtriangle_t triangles[MAXALIASTRIS];
|
#define VANILLA_MAXALIASVERTS 1024
|
||||||
extern trivertx_t *poseverts[MAXALIASFRAMES];
|
#define MAXALIASVERTS 65536 // spike -- was 2000 //johnfitz -- was 1024
|
||||||
|
#define MAXALIASFRAMES 1024 //spike -- was 256
|
||||||
|
extern stvert_t stverts[MAXALIASVERTS];
|
||||||
|
extern mtriangle_t *triangles;
|
||||||
|
extern trivertx_t *poseverts_mdl[MAXALIASFRAMES];
|
||||||
|
extern md3XyzNormal_t *poseverts_md3[MAXALIASFRAMES];
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
|
|
||||||
|
@ -388,8 +394,9 @@ extern trivertx_t *poseverts[MAXALIASFRAMES];
|
||||||
// Whole model
|
// Whole model
|
||||||
//
|
//
|
||||||
|
|
||||||
typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;
|
typedef enum {mod_brush, mod_sprite, mod_alias, mod_ext_invalid} modtype_t;
|
||||||
|
|
||||||
|
//Spike -- these are misnamed/ambiguous.
|
||||||
#define EF_ROCKET 1 // leave a trail
|
#define EF_ROCKET 1 // leave a trail
|
||||||
#define EF_GRENADE 2 // leave a trail
|
#define EF_GRENADE 2 // leave a trail
|
||||||
#define EF_GIB 4 // leave a trail
|
#define EF_GIB 4 // leave a trail
|
||||||
|
@ -405,6 +412,10 @@ typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;
|
||||||
#define MOD_NOSHADOW 512 //don't cast a shadow
|
#define MOD_NOSHADOW 512 //don't cast a shadow
|
||||||
#define MOD_FBRIGHTHACK 1024 //when fullbrights are disabled, use a hack to render this model brighter
|
#define MOD_FBRIGHTHACK 1024 //when fullbrights are disabled, use a hack to render this model brighter
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
//spike -- added this for particle stuff
|
||||||
|
#define MOD_EMITREPLACE 2048 //particle effect completely replaces the model (for flames or whatever).
|
||||||
|
#define MOD_EMITFORWARDS 4096 //particle effect is emitted forwards, rather than downwards. why down? good question.
|
||||||
|
//spike
|
||||||
|
|
||||||
typedef struct qmodel_s
|
typedef struct qmodel_s
|
||||||
{
|
{
|
||||||
|
@ -419,6 +430,13 @@ typedef struct qmodel_s
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
int emiteffect; //spike -- this effect is emitted per-frame by entities with this model
|
||||||
|
int traileffect; //spike -- this effect is used when entities move
|
||||||
|
struct skytris_s *skytris; //spike -- surface-based particle emission for this model
|
||||||
|
struct skytriblock_s *skytrimem; //spike -- surface-based particle emission for this model (for better cache performance+less allocs)
|
||||||
|
double skytime; //doesn't really cope with multiples. oh well...
|
||||||
|
#endif
|
||||||
//
|
//
|
||||||
// volume occupied by the model graphics
|
// volume occupied by the model graphics
|
||||||
//
|
//
|
||||||
|
@ -439,7 +457,7 @@ typedef struct qmodel_s
|
||||||
int firstmodelsurface, nummodelsurfaces;
|
int firstmodelsurface, nummodelsurfaces;
|
||||||
|
|
||||||
int numsubmodels;
|
int numsubmodels;
|
||||||
dmodel_t *submodels;
|
mmodel_t *submodels;
|
||||||
|
|
||||||
int numplanes;
|
int numplanes;
|
||||||
mplane_t *planes;
|
mplane_t *planes;
|
||||||
|
@ -483,16 +501,16 @@ typedef struct qmodel_s
|
||||||
qboolean viswarn; // for Mod_DecompressVis()
|
qboolean viswarn; // for Mod_DecompressVis()
|
||||||
|
|
||||||
int bspversion;
|
int bspversion;
|
||||||
|
int contentstransparent; //spike -- added this so we can disable glitchy wateralpha where its not supported.
|
||||||
|
|
||||||
//
|
//
|
||||||
// alias model
|
// alias model
|
||||||
//
|
//
|
||||||
|
|
||||||
GLuint meshvbo;
|
GLuint meshvbo;
|
||||||
GLuint meshindexesvbo;
|
byte *meshvboptr; //for non-vbo fallback.
|
||||||
int vboindexofs; // offset in vbo of the hdr->numindexes unsigned shorts
|
GLuint meshindexesvbo;
|
||||||
int vboxyzofs; // offset in vbo of hdr->numposes*hdr->numverts_vbo meshxyz_t
|
byte *meshindexesvboptr; //for non-ebo fallback.
|
||||||
int vbostofs; // offset in vbo of hdr->numverts_vbo meshst_t
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// additional model data
|
// additional model data
|
||||||
|
|
|
@ -208,8 +208,37 @@ void R_StoreEfrags (efrag_t **ppefrag)
|
||||||
{
|
{
|
||||||
pent = pefrag->entity;
|
pent = pefrag->entity;
|
||||||
|
|
||||||
if ((pent->visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS))
|
if ((pent->visframe != r_framecount) && (cl_numvisedicts < cl_maxvisedicts))
|
||||||
{
|
{
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
if (pent->netstate.emiteffectnum > 0)
|
||||||
|
{
|
||||||
|
float t = cl.time-cl.oldtime;
|
||||||
|
vec3_t axis[3];
|
||||||
|
if (t < 0) t = 0; else if (t > 0.1) t= 0.1;
|
||||||
|
AngleVectors(pent->angles, axis[0], axis[1], axis[2]);
|
||||||
|
if (pent->model->type == mod_alias)
|
||||||
|
axis[0][2] *= -1; //stupid vanilla bug
|
||||||
|
PScript_RunParticleEffectState(pent->origin, axis[0], t, cl.particle_precache[pent->netstate.emiteffectnum].index, &pent->emitstate);
|
||||||
|
}
|
||||||
|
else if (pent->model->emiteffect >= 0)
|
||||||
|
{
|
||||||
|
float t = cl.time-cl.oldtime;
|
||||||
|
vec3_t axis[3];
|
||||||
|
if (t < 0) t = 0; else if (t > 0.1) t= 0.1;
|
||||||
|
AngleVectors(pent->angles, axis[0], axis[1], axis[2]);
|
||||||
|
if (pent->model->flags & MOD_EMITFORWARDS)
|
||||||
|
{
|
||||||
|
if (pent->model->type == mod_alias)
|
||||||
|
axis[0][2] *= -1; //stupid vanilla bug
|
||||||
|
}
|
||||||
|
else
|
||||||
|
VectorScale(axis[2], -1, axis[0]);
|
||||||
|
PScript_RunParticleEffectState(pent->origin, axis[0], t, pent->model->emiteffect, &pent->emitstate);
|
||||||
|
if (pent->model->flags & MOD_EMITREPLACE)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
cl_visedicts[cl_numvisedicts++] = pent;
|
cl_visedicts[cl_numvisedicts++] = pent;
|
||||||
pent->visframe = r_framecount;
|
pent->visframe = r_framecount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,8 @@ void R_MarkLights (dlight_t *light, int num, mnode_t *node)
|
||||||
msurface_t *surf;
|
msurface_t *surf;
|
||||||
vec3_t impact;
|
vec3_t impact;
|
||||||
float dist, l, maxdist;
|
float dist, l, maxdist;
|
||||||
int i, j, s, t;
|
unsigned int i;
|
||||||
|
int j, s, t;
|
||||||
|
|
||||||
start:
|
start:
|
||||||
|
|
||||||
|
@ -311,7 +312,8 @@ loc0:
|
||||||
return true; // hit something
|
return true; // hit something
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i, ds, dt;
|
unsigned int i;
|
||||||
|
int ds, dt;
|
||||||
msurface_t *surf;
|
msurface_t *surf;
|
||||||
// check for impact on this node
|
// check for impact on this node
|
||||||
VectorCopy (mid, lightspot);
|
VectorCopy (mid, lightspot);
|
||||||
|
|
|
@ -109,6 +109,7 @@ cvar_t r_telealpha = {"r_telealpha","0",CVAR_NONE};
|
||||||
cvar_t r_slimealpha = {"r_slimealpha","0",CVAR_NONE};
|
cvar_t r_slimealpha = {"r_slimealpha","0",CVAR_NONE};
|
||||||
|
|
||||||
float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha;
|
float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha;
|
||||||
|
float map_fallbackalpha;
|
||||||
|
|
||||||
qboolean r_drawflat_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe, r_drawworld_cheatsafe; //johnfitz
|
qboolean r_drawflat_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe, r_drawworld_cheatsafe; //johnfitz
|
||||||
|
|
||||||
|
@ -347,12 +348,15 @@ qboolean R_CullModelForEntity (entity_t *e)
|
||||||
R_RotateForEntity -- johnfitz -- modified to take origin and angles instead of pointer to entity
|
R_RotateForEntity -- johnfitz -- modified to take origin and angles instead of pointer to entity
|
||||||
===============
|
===============
|
||||||
*/
|
*/
|
||||||
void R_RotateForEntity (vec3_t origin, vec3_t angles)
|
void R_RotateForEntity (vec3_t origin, vec3_t angles, unsigned char scale)
|
||||||
{
|
{
|
||||||
glTranslatef (origin[0], origin[1], origin[2]);
|
glTranslatef (origin[0], origin[1], origin[2]);
|
||||||
glRotatef (angles[1], 0, 0, 1);
|
glRotatef (angles[1], 0, 0, 1);
|
||||||
glRotatef (-angles[0], 0, 1, 0);
|
glRotatef (-angles[0], 0, 1, 0);
|
||||||
glRotatef (angles[2], 1, 0, 0);
|
glRotatef (angles[2], 1, 0, 0);
|
||||||
|
|
||||||
|
if (scale != 16)
|
||||||
|
glScalef (scale/16.0, scale/16.0, scale/16.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -635,7 +639,7 @@ void R_DrawEntitiesOnList (qboolean alphapass) //johnfitz -- added parameter
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//johnfitz -- chasecam
|
//johnfitz -- chasecam
|
||||||
if (currententity == &cl_entities[cl.viewentity])
|
if (currententity == &cl.entities[cl.viewentity])
|
||||||
currententity->angles[0] *= 0.3;
|
currententity->angles[0] *= 0.3;
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
|
||||||
|
@ -650,6 +654,9 @@ void R_DrawEntitiesOnList (qboolean alphapass) //johnfitz -- added parameter
|
||||||
case mod_sprite:
|
case mod_sprite:
|
||||||
R_DrawSpriteModel (currententity);
|
R_DrawSpriteModel (currententity);
|
||||||
break;
|
break;
|
||||||
|
case mod_ext_invalid:
|
||||||
|
//nothing. could draw a blob instead.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -812,7 +819,7 @@ void R_ShowTris (void)
|
||||||
{
|
{
|
||||||
currententity = cl_visedicts[i];
|
currententity = cl_visedicts[i];
|
||||||
|
|
||||||
if (currententity == &cl_entities[cl.viewentity]) // chasecam
|
if (currententity == &cl.entities[cl.viewentity]) // chasecam
|
||||||
currententity->angles[0] *= 0.3;
|
currententity->angles[0] *= 0.3;
|
||||||
|
|
||||||
switch (currententity->model->type)
|
switch (currententity->model->type)
|
||||||
|
@ -931,6 +938,9 @@ void R_RenderScene (void)
|
||||||
R_RenderDlights (); //triangle fan dlights -- johnfitz -- moved after water
|
R_RenderDlights (); //triangle fan dlights -- johnfitz -- moved after water
|
||||||
|
|
||||||
R_DrawParticles ();
|
R_DrawParticles ();
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
PScript_DrawParticles();
|
||||||
|
#endif
|
||||||
|
|
||||||
Fog_DisableGFog (); //johnfitz
|
Fog_DisableGFog (); //johnfitz
|
||||||
|
|
||||||
|
@ -1120,9 +1130,9 @@ void R_RenderView (void)
|
||||||
time2 = Sys_DoubleTime ();
|
time2 = Sys_DoubleTime ();
|
||||||
if (r_pos.value)
|
if (r_pos.value)
|
||||||
Con_Printf ("x %i y %i z %i (pitch %i yaw %i roll %i)\n",
|
Con_Printf ("x %i y %i z %i (pitch %i yaw %i roll %i)\n",
|
||||||
(int)cl_entities[cl.viewentity].origin[0],
|
(int)cl.entities[cl.viewentity].origin[0],
|
||||||
(int)cl_entities[cl.viewentity].origin[1],
|
(int)cl.entities[cl.viewentity].origin[1],
|
||||||
(int)cl_entities[cl.viewentity].origin[2],
|
(int)cl.entities[cl.viewentity].origin[2],
|
||||||
(int)cl.viewangles[PITCH],
|
(int)cl.viewangles[PITCH],
|
||||||
(int)cl.viewangles[YAW],
|
(int)cl.viewangles[YAW],
|
||||||
(int)cl.viewangles[ROLL]);
|
(int)cl.viewangles[ROLL]);
|
||||||
|
|
|
@ -116,7 +116,10 @@ R_SetWateralpha_f -- ericw
|
||||||
*/
|
*/
|
||||||
static void R_SetWateralpha_f (cvar_t *var)
|
static void R_SetWateralpha_f (cvar_t *var)
|
||||||
{
|
{
|
||||||
|
if (cls.signon == SIGNONS && cl.worldmodel && !(cl.worldmodel->contentstransparent&SURF_DRAWWATER) && var->value < 1)
|
||||||
|
Con_Warning("Map does not appear to be water-vised\n");
|
||||||
map_wateralpha = var->value;
|
map_wateralpha = var->value;
|
||||||
|
map_fallbackalpha = var->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -126,6 +129,8 @@ R_SetLavaalpha_f -- ericw
|
||||||
*/
|
*/
|
||||||
static void R_SetLavaalpha_f (cvar_t *var)
|
static void R_SetLavaalpha_f (cvar_t *var)
|
||||||
{
|
{
|
||||||
|
if (cls.signon == SIGNONS && cl.worldmodel && !(cl.worldmodel->contentstransparent&SURF_DRAWLAVA) && var->value && var->value < 1)
|
||||||
|
Con_Warning("Map does not appear to be lava-vised\n");
|
||||||
map_lavaalpha = var->value;
|
map_lavaalpha = var->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +141,8 @@ R_SetTelealpha_f -- ericw
|
||||||
*/
|
*/
|
||||||
static void R_SetTelealpha_f (cvar_t *var)
|
static void R_SetTelealpha_f (cvar_t *var)
|
||||||
{
|
{
|
||||||
|
if (cls.signon == SIGNONS && cl.worldmodel && !(cl.worldmodel->contentstransparent&SURF_DRAWTELE) && var->value && var->value < 1)
|
||||||
|
Con_Warning("Map does not appear to be tele-vised\n");
|
||||||
map_telealpha = var->value;
|
map_telealpha = var->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +153,8 @@ R_SetSlimealpha_f -- ericw
|
||||||
*/
|
*/
|
||||||
static void R_SetSlimealpha_f (cvar_t *var)
|
static void R_SetSlimealpha_f (cvar_t *var)
|
||||||
{
|
{
|
||||||
|
if (cls.signon == SIGNONS && cl.worldmodel && !(cl.worldmodel->contentstransparent&SURF_DRAWSLIME) && var->value && var->value < 1)
|
||||||
|
Con_Warning("Map does not appear to be slime-vised\n");
|
||||||
map_slimealpha = var->value;
|
map_slimealpha = var->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,13 +166,13 @@ GL_WaterAlphaForSurfface -- ericw
|
||||||
float GL_WaterAlphaForSurface (msurface_t *fa)
|
float GL_WaterAlphaForSurface (msurface_t *fa)
|
||||||
{
|
{
|
||||||
if (fa->flags & SURF_DRAWLAVA)
|
if (fa->flags & SURF_DRAWLAVA)
|
||||||
return map_lavaalpha > 0 ? map_lavaalpha : map_wateralpha;
|
return map_lavaalpha > 0 ? map_lavaalpha : map_fallbackalpha;
|
||||||
else if (fa->flags & SURF_DRAWTELE)
|
else if (fa->flags & SURF_DRAWTELE)
|
||||||
return map_telealpha > 0 ? map_telealpha : map_wateralpha;
|
return map_telealpha > 0 ? map_telealpha : map_fallbackalpha;
|
||||||
else if (fa->flags & SURF_DRAWSLIME)
|
else if (fa->flags & SURF_DRAWSLIME)
|
||||||
return map_slimealpha > 0 ? map_slimealpha : map_wateralpha;
|
return map_slimealpha > 0 ? map_slimealpha : map_fallbackalpha;
|
||||||
else
|
else
|
||||||
return map_wateralpha;
|
return map_wateralpha;// > 0 ? map_wateralpha : map_fallbackalpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -242,6 +251,9 @@ void R_Init (void)
|
||||||
Cvar_SetCallback (&r_slimealpha, R_SetSlimealpha_f);
|
Cvar_SetCallback (&r_slimealpha, R_SetSlimealpha_f);
|
||||||
|
|
||||||
R_InitParticles ();
|
R_InitParticles ();
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
PScript_InitParticles();
|
||||||
|
#endif
|
||||||
R_SetClearColor_f (&r_clearcolor); //johnfitz
|
R_SetClearColor_f (&r_clearcolor); //johnfitz
|
||||||
|
|
||||||
Sky_Init (); //johnfitz
|
Sky_Init (); //johnfitz
|
||||||
|
@ -281,7 +293,7 @@ void R_TranslateNewPlayerSkin (int playernum)
|
||||||
int skinnum;
|
int skinnum;
|
||||||
|
|
||||||
//get correct texture pixels
|
//get correct texture pixels
|
||||||
currententity = &cl_entities[1+playernum];
|
currententity = &cl.entities[1+playernum];
|
||||||
|
|
||||||
if (!currententity->model || currententity->model->type != mod_alias)
|
if (!currententity->model || currententity->model->type != mod_alias)
|
||||||
return;
|
return;
|
||||||
|
@ -290,19 +302,28 @@ void R_TranslateNewPlayerSkin (int playernum)
|
||||||
|
|
||||||
skinnum = currententity->skinnum;
|
skinnum = currententity->skinnum;
|
||||||
|
|
||||||
//TODO: move these tests to the place where skinnum gets received from the server
|
if (paliashdr->numskins)
|
||||||
if (skinnum < 0 || skinnum >= paliashdr->numskins)
|
|
||||||
{
|
{
|
||||||
Con_DPrintf("(%d): Invalid player skin #%d\n", playernum, skinnum);
|
//TODO: move these tests to the place where skinnum gets received from the server
|
||||||
skinnum = 0;
|
if (skinnum < 0 || skinnum >= paliashdr->numskins)
|
||||||
|
{
|
||||||
|
Con_DPrintf("(%d): Invalid player skin #%d\n", playernum, skinnum);
|
||||||
|
skinnum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixels = (byte *)paliashdr + paliashdr->texels[skinnum]; // This is not a persistent place!
|
||||||
|
|
||||||
|
//upload new image
|
||||||
|
q_snprintf(name, sizeof(name), "player_%i", playernum);
|
||||||
|
playertextures[playernum] = TexMgr_LoadImage (currententity->model, name, paliashdr->skinwidth, paliashdr->skinheight,
|
||||||
|
SRC_INDEXED, pixels, paliashdr->gltextures[skinnum][0]->source_file, paliashdr->gltextures[skinnum][0]->source_offset, TEXPREF_PAD | TEXPREF_OVERWRITE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
q_snprintf(name, sizeof(name), "player_%i", playernum);
|
||||||
|
playertextures[playernum] = TexMgr_LoadImage (currententity->model, name, paliashdr->skinwidth, paliashdr->skinheight,
|
||||||
|
SRC_EXTERNAL, NULL, "skins/base.pcx", 0, TEXPREF_PAD | TEXPREF_OVERWRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixels = (byte *)paliashdr + paliashdr->texels[skinnum]; // This is not a persistent place!
|
|
||||||
|
|
||||||
//upload new image
|
|
||||||
q_snprintf(name, sizeof(name), "player_%i", playernum);
|
|
||||||
playertextures[playernum] = TexMgr_LoadImage (currententity->model, name, paliashdr->skinwidth, paliashdr->skinheight,
|
|
||||||
SRC_INDEXED, pixels, paliashdr->gltextures[skinnum][0]->source_file, paliashdr->gltextures[skinnum][0]->source_offset, TEXPREF_PAD | TEXPREF_OVERWRITE);
|
|
||||||
|
|
||||||
//now recolor it
|
//now recolor it
|
||||||
R_TranslatePlayerSkin (playernum);
|
R_TranslatePlayerSkin (playernum);
|
||||||
|
@ -334,10 +355,11 @@ static void R_ParseWorldspawn (void)
|
||||||
char key[128], value[4096];
|
char key[128], value[4096];
|
||||||
const char *data;
|
const char *data;
|
||||||
|
|
||||||
map_wateralpha = r_wateralpha.value;
|
map_fallbackalpha = r_wateralpha.value;
|
||||||
map_lavaalpha = r_lavaalpha.value;
|
map_wateralpha = (cl.worldmodel->contentstransparent&SURF_DRAWWATER)?r_wateralpha.value:1;
|
||||||
map_telealpha = r_telealpha.value;
|
map_lavaalpha = (cl.worldmodel->contentstransparent&SURF_DRAWLAVA)?r_lavaalpha.value:1;
|
||||||
map_slimealpha = r_slimealpha.value;
|
map_telealpha = (cl.worldmodel->contentstransparent&SURF_DRAWTELE)?r_telealpha.value:1;
|
||||||
|
map_slimealpha = (cl.worldmodel->contentstransparent&SURF_DRAWSLIME)?r_slimealpha.value:1;
|
||||||
|
|
||||||
data = COM_Parse(cl.worldmodel->entities);
|
data = COM_Parse(cl.worldmodel->entities);
|
||||||
if (!data)
|
if (!data)
|
||||||
|
@ -363,7 +385,7 @@ static void R_ParseWorldspawn (void)
|
||||||
q_strlcpy(value, com_token, sizeof(value));
|
q_strlcpy(value, com_token, sizeof(value));
|
||||||
|
|
||||||
if (!strcmp("wateralpha", key))
|
if (!strcmp("wateralpha", key))
|
||||||
map_wateralpha = atof(value);
|
map_fallbackalpha = map_wateralpha = atof(value);
|
||||||
|
|
||||||
if (!strcmp("lavaalpha", key))
|
if (!strcmp("lavaalpha", key))
|
||||||
map_lavaalpha = atof(value);
|
map_lavaalpha = atof(value);
|
||||||
|
@ -396,6 +418,9 @@ void R_NewMap (void)
|
||||||
|
|
||||||
r_viewleaf = NULL;
|
r_viewleaf = NULL;
|
||||||
R_ClearParticles ();
|
R_ClearParticles ();
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
PScript_ClearParticles();
|
||||||
|
#endif
|
||||||
|
|
||||||
GL_BuildLightmaps ();
|
GL_BuildLightmaps ();
|
||||||
GL_BuildBModelVertexBuffer ();
|
GL_BuildBModelVertexBuffer ();
|
||||||
|
@ -498,7 +523,7 @@ GLint GL_GetUniformLocation (GLuint *programPtr, const char *name)
|
||||||
{
|
{
|
||||||
GLint location;
|
GLint location;
|
||||||
|
|
||||||
if (!programPtr)
|
if (!*programPtr)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
location = GL_GetUniformLocationFunc(*programPtr, name);
|
location = GL_GetUniformLocationFunc(*programPtr, name);
|
||||||
|
|
|
@ -134,6 +134,10 @@ float scr_centertime_off;
|
||||||
int scr_center_lines;
|
int scr_center_lines;
|
||||||
int scr_erase_lines;
|
int scr_erase_lines;
|
||||||
int scr_erase_center;
|
int scr_erase_center;
|
||||||
|
#define CPRINT_TYPEWRITER (1u<<0)
|
||||||
|
#define CPRINT_PERSIST (1u<<1)
|
||||||
|
#define CPRINT_TALIGN (1u<<2)
|
||||||
|
unsigned int scr_centerprint_flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============
|
==============
|
||||||
|
@ -145,10 +149,87 @@ for a few moments
|
||||||
*/
|
*/
|
||||||
void SCR_CenterPrint (const char *str) //update centerprint data
|
void SCR_CenterPrint (const char *str) //update centerprint data
|
||||||
{
|
{
|
||||||
|
unsigned int flags = 0;
|
||||||
|
|
||||||
|
if (*str != '/' && cl.intermission)
|
||||||
|
flags |= CPRINT_TYPEWRITER | CPRINT_PERSIST | CPRINT_TALIGN;
|
||||||
|
|
||||||
|
//check for centerprint prefixes/flags
|
||||||
|
while (*str == '/')
|
||||||
|
{
|
||||||
|
if (str[1] == '.')
|
||||||
|
{ //no more
|
||||||
|
str+=2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (str[1] == 'P')
|
||||||
|
flags |= CPRINT_PERSIST;
|
||||||
|
else if (str[1] == 'W') //typewriter
|
||||||
|
flags ^= CPRINT_TYPEWRITER;
|
||||||
|
else if (str[1] == 'S') //typewriter
|
||||||
|
flags ^= CPRINT_PERSIST;
|
||||||
|
else if (str[1] == 'M') //masked background
|
||||||
|
;
|
||||||
|
else if (str[1] == 'O') //obituary print (lower half)
|
||||||
|
;
|
||||||
|
else if (str[1] == 'B') //bottom-align
|
||||||
|
;
|
||||||
|
else if (str[1] == 'B') //top-align
|
||||||
|
;
|
||||||
|
else if (str[1] == 'L') //left-align
|
||||||
|
;
|
||||||
|
else if (str[1] == 'R') //right-align
|
||||||
|
;
|
||||||
|
else if (str[1] == 'F') //alternative 'finale' control
|
||||||
|
{
|
||||||
|
str+=2;
|
||||||
|
if (!cl.intermission)
|
||||||
|
cl.completed_time = cl.time;
|
||||||
|
switch(*str++)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
str--;
|
||||||
|
break;
|
||||||
|
case 'R': //remove intermission (no other method to do this)
|
||||||
|
cl.intermission = 0;
|
||||||
|
break;
|
||||||
|
case 'I': //regular intermission
|
||||||
|
case 'S': //show scoreboard
|
||||||
|
cl.intermission = 1;
|
||||||
|
break;
|
||||||
|
case 'F': //like svc_finale
|
||||||
|
cl.intermission = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; //any other flag you want
|
||||||
|
}
|
||||||
|
vid.recalc_refdef = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (str[1] == 'I') //title image
|
||||||
|
{
|
||||||
|
const char *e;
|
||||||
|
str+=2;
|
||||||
|
e = strchr(str, ':');
|
||||||
|
if (!e)
|
||||||
|
e = strchr(str, ' '); //probably an error
|
||||||
|
if (!e)
|
||||||
|
e = str+strlen(str)-1; //error
|
||||||
|
str = e+1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
str+=2;
|
||||||
|
}
|
||||||
|
|
||||||
strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
|
strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
|
||||||
scr_centertime_off = scr_centertime.value;
|
scr_centertime_off = (flags&CPRINT_PERSIST)?999999:scr_centertime.value;
|
||||||
scr_centertime_start = cl.time;
|
scr_centertime_start = cl.time;
|
||||||
|
|
||||||
|
if (*scr_centerstring && !(flags&CPRINT_PERSIST))
|
||||||
|
Con_LogCenterPrint (scr_centerstring);
|
||||||
|
|
||||||
// count the number of lines for centering
|
// count the number of lines for centering
|
||||||
scr_center_lines = 1;
|
scr_center_lines = 1;
|
||||||
str = scr_centerstring;
|
str = scr_centerstring;
|
||||||
|
@ -241,8 +322,12 @@ float AdaptFovx (float fov_x, float width, float height)
|
||||||
{
|
{
|
||||||
float a, x;
|
float a, x;
|
||||||
|
|
||||||
if (fov_x < 1 || fov_x > 179)
|
if (cl.statsf[STAT_VIEWZOOM])
|
||||||
Sys_Error ("Bad fov: %f", fov_x);
|
fov_x *= cl.statsf[STAT_VIEWZOOM]/255.0;
|
||||||
|
if (fov_x < 1)
|
||||||
|
fov_x = 1;
|
||||||
|
if (fov_x > 179)
|
||||||
|
fov_x = 179;
|
||||||
|
|
||||||
if (!scr_fov_adapt.value)
|
if (!scr_fov_adapt.value)
|
||||||
return fov_x;
|
return fov_x;
|
||||||
|
|
|
@ -101,7 +101,7 @@ void Sky_LoadTexture (texture_t *mt)
|
||||||
static byte back_data[128*128]; //FIXME: Hunk_Alloc
|
static byte back_data[128*128]; //FIXME: Hunk_Alloc
|
||||||
unsigned *rgba;
|
unsigned *rgba;
|
||||||
|
|
||||||
src = (byte *)mt + mt->offsets[0];
|
src = (byte *)(mt+1);
|
||||||
|
|
||||||
// extract back layer and upload
|
// extract back layer and upload
|
||||||
for (i=0 ; i<128 ; i++)
|
for (i=0 ; i<128 ; i++)
|
||||||
|
@ -155,6 +155,7 @@ void Sky_LoadSkyBox (const char *name)
|
||||||
char filename[MAX_OSPATH];
|
char filename[MAX_OSPATH];
|
||||||
byte *data;
|
byte *data;
|
||||||
qboolean nonefound = true;
|
qboolean nonefound = true;
|
||||||
|
qboolean malloced;
|
||||||
|
|
||||||
if (strcmp(skybox_name, name) == 0)
|
if (strcmp(skybox_name, name) == 0)
|
||||||
return; //no change
|
return; //no change
|
||||||
|
@ -179,7 +180,7 @@ void Sky_LoadSkyBox (const char *name)
|
||||||
{
|
{
|
||||||
mark = Hunk_LowMark ();
|
mark = Hunk_LowMark ();
|
||||||
q_snprintf (filename, sizeof(filename), "gfx/env/%s%s", name, suf[i]);
|
q_snprintf (filename, sizeof(filename), "gfx/env/%s%s", name, suf[i]);
|
||||||
data = Image_LoadImage (filename, &width, &height);
|
data = Image_LoadImage (filename, &width, &height, &malloced);
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
skybox_textures[i] = TexMgr_LoadImage (cl.worldmodel, filename, width, height, SRC_RGBA, data, filename, 0, TEXPREF_NONE);
|
skybox_textures[i] = TexMgr_LoadImage (cl.worldmodel, filename, width, height, SRC_RGBA, data, filename, 0, TEXPREF_NONE);
|
||||||
|
@ -190,6 +191,8 @@ void Sky_LoadSkyBox (const char *name)
|
||||||
Con_Printf ("Couldn't load %s\n", filename);
|
Con_Printf ("Couldn't load %s\n", filename);
|
||||||
skybox_textures[i] = notexture;
|
skybox_textures[i] = notexture;
|
||||||
}
|
}
|
||||||
|
if (malloced)
|
||||||
|
free(data);
|
||||||
Hunk_FreeToLowMark (mark);
|
Hunk_FreeToLowMark (mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -810,6 +810,8 @@ TexMgr_AlphaEdgeFix
|
||||||
|
|
||||||
eliminate pink edges on sprites, etc.
|
eliminate pink edges on sprites, etc.
|
||||||
operates in place on 32bit data
|
operates in place on 32bit data
|
||||||
|
|
||||||
|
spike -- small note that would be better to use premultiplied alpha to completely eliminate these skirts without the possibility of misbehaving.
|
||||||
===============
|
===============
|
||||||
*/
|
*/
|
||||||
static void TexMgr_AlphaEdgeFix (byte *data, int width, int height)
|
static void TexMgr_AlphaEdgeFix (byte *data, int width, int height)
|
||||||
|
@ -1006,6 +1008,23 @@ static byte *TexMgr_PadImageH (byte *in, int width, int height, byte padbyte)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static byte *TexMgr_PreMultiply32(byte *in, size_t width, size_t height)
|
||||||
|
{
|
||||||
|
size_t pixels = width * height;
|
||||||
|
byte *out = (byte *) Hunk_Alloc(pixels*4);
|
||||||
|
byte *result = out;
|
||||||
|
while (pixels --> 0)
|
||||||
|
{
|
||||||
|
out[0] = (in[0]*in[3])>>8;
|
||||||
|
out[1] = (in[1]*in[3])>>8;
|
||||||
|
out[2] = (in[2]*in[3])>>8;
|
||||||
|
out[3] = in[3];
|
||||||
|
in += 4;
|
||||||
|
out += 4;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
TexMgr_LoadImage32 -- handles 32bit source data
|
TexMgr_LoadImage32 -- handles 32bit source data
|
||||||
|
@ -1015,6 +1034,10 @@ static void TexMgr_LoadImage32 (gltexture_t *glt, unsigned *data)
|
||||||
{
|
{
|
||||||
int internalformat, miplevel, mipwidth, mipheight, picmip;
|
int internalformat, miplevel, mipwidth, mipheight, picmip;
|
||||||
|
|
||||||
|
//do this before any rescaling
|
||||||
|
if (glt->flags & TEXPREF_PREMULTIPLY)
|
||||||
|
data = (unsigned*)TexMgr_PreMultiply32((byte*)data, glt->width, glt->height);
|
||||||
|
|
||||||
if (!gl_texture_NPOT)
|
if (!gl_texture_NPOT)
|
||||||
{
|
{
|
||||||
// resample up
|
// resample up
|
||||||
|
@ -1156,7 +1179,7 @@ static void TexMgr_LoadImage8 (gltexture_t *glt, byte *data)
|
||||||
data = (byte *)TexMgr_8to32(data, glt->width * glt->height, usepal);
|
data = (byte *)TexMgr_8to32(data, glt->width * glt->height, usepal);
|
||||||
|
|
||||||
// fix edges
|
// fix edges
|
||||||
if (glt->flags & TEXPREF_ALPHA)
|
if ((glt->flags & TEXPREF_ALPHA) && !(glt->flags & TEXPREF_PREMULTIPLY))
|
||||||
TexMgr_AlphaEdgeFix (data, glt->width, glt->height);
|
TexMgr_AlphaEdgeFix (data, glt->width, glt->height);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1196,6 +1219,7 @@ gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int
|
||||||
unsigned short crc;
|
unsigned short crc;
|
||||||
gltexture_t *glt;
|
gltexture_t *glt;
|
||||||
int mark;
|
int mark;
|
||||||
|
qboolean malloced;
|
||||||
|
|
||||||
if (isDedicated)
|
if (isDedicated)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1212,6 +1236,7 @@ gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int
|
||||||
case SRC_RGBA:
|
case SRC_RGBA:
|
||||||
crc = CRC_Block(data, width * height * 4);
|
crc = CRC_Block(data, width * height * 4);
|
||||||
break;
|
break;
|
||||||
|
case SRC_EXTERNAL:
|
||||||
default: /* not reachable but avoids compiler warnings */
|
default: /* not reachable but avoids compiler warnings */
|
||||||
crc = 0;
|
crc = 0;
|
||||||
}
|
}
|
||||||
|
@ -1249,6 +1274,24 @@ gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int
|
||||||
case SRC_LIGHTMAP:
|
case SRC_LIGHTMAP:
|
||||||
TexMgr_LoadLightmap (glt, data);
|
TexMgr_LoadLightmap (glt, data);
|
||||||
break;
|
break;
|
||||||
|
case SRC_EXTERNAL:
|
||||||
|
data = Image_LoadImage (glt->source_file, (int *)&glt->source_width, (int *)&glt->source_height, &malloced); //simple file
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
glt->source_width = glt->source_height = 1;
|
||||||
|
glt->width = glt->source_width;
|
||||||
|
glt->height = glt->source_height;
|
||||||
|
TexMgr_LoadImage8 (glt, (byte*)"\x07");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glt->width = glt->source_width;
|
||||||
|
glt->height = glt->source_height;
|
||||||
|
TexMgr_LoadImage32 (glt, (unsigned *)data);
|
||||||
|
if (malloced)
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SRC_RGBA:
|
case SRC_RGBA:
|
||||||
TexMgr_LoadImage32 (glt, (unsigned *)data);
|
TexMgr_LoadImage32 (glt, (unsigned *)data);
|
||||||
break;
|
break;
|
||||||
|
@ -1277,6 +1320,7 @@ void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants)
|
||||||
byte translation[256];
|
byte translation[256];
|
||||||
byte *src, *dst, *data = NULL, *translated;
|
byte *src, *dst, *data = NULL, *translated;
|
||||||
int mark, size, i;
|
int mark, size, i;
|
||||||
|
qboolean malloced = false;
|
||||||
//
|
//
|
||||||
// get source data
|
// get source data
|
||||||
//
|
//
|
||||||
|
@ -1302,7 +1346,7 @@ void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants)
|
||||||
fclose (f);
|
fclose (f);
|
||||||
}
|
}
|
||||||
else if (glt->source_file[0] && !glt->source_offset)
|
else if (glt->source_file[0] && !glt->source_offset)
|
||||||
data = Image_LoadImage (glt->source_file, (int *)&glt->source_width, (int *)&glt->source_height); //simple file
|
data = Image_LoadImage (glt->source_file, (int *)&glt->source_width, (int *)&glt->source_height, &malloced); //simple file
|
||||||
else if (!glt->source_file[0] && glt->source_offset)
|
else if (!glt->source_file[0] && glt->source_offset)
|
||||||
data = (byte *) glt->source_offset; //image in memory
|
data = (byte *) glt->source_offset; //image in memory
|
||||||
|
|
||||||
|
@ -1382,11 +1426,14 @@ invalid:
|
||||||
case SRC_LIGHTMAP:
|
case SRC_LIGHTMAP:
|
||||||
TexMgr_LoadLightmap (glt, data);
|
TexMgr_LoadLightmap (glt, data);
|
||||||
break;
|
break;
|
||||||
|
case SRC_EXTERNAL:
|
||||||
case SRC_RGBA:
|
case SRC_RGBA:
|
||||||
TexMgr_LoadImage32 (glt, (unsigned *)data);
|
TexMgr_LoadImage32 (glt, (unsigned *)data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (malloced)
|
||||||
|
free(data);
|
||||||
Hunk_FreeToLowMark(mark);
|
Hunk_FreeToLowMark(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define TEXPREF_NOBRIGHT 0x0200 // use nobright mask palette
|
#define TEXPREF_NOBRIGHT 0x0200 // use nobright mask palette
|
||||||
#define TEXPREF_CONCHARS 0x0400 // use conchars palette
|
#define TEXPREF_CONCHARS 0x0400 // use conchars palette
|
||||||
#define TEXPREF_WARPIMAGE 0x0800 // resize this texture when warpimagesize changes
|
#define TEXPREF_WARPIMAGE 0x0800 // resize this texture when warpimagesize changes
|
||||||
|
#define TEXPREF_PREMULTIPLY 0x1000 // rgb = rgb*a; a=a;
|
||||||
|
|
||||||
enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA};
|
enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA, SRC_EXTERNAL};
|
||||||
|
|
||||||
typedef uintptr_t src_offset_t;
|
typedef uintptr_t src_offset_t;
|
||||||
|
|
||||||
|
|
|
@ -607,7 +607,7 @@ static qboolean VID_SetMode (int width, int height, int refreshrate, int bpp, qb
|
||||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, fsaa > 0 ? 1 : 0);
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, fsaa > 0 ? 1 : 0);
|
||||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fsaa);
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fsaa);
|
||||||
|
|
||||||
q_snprintf(caption, sizeof(caption), "QuakeSpasm " QUAKESPASM_VER_STRING);
|
q_snprintf(caption, sizeof(caption), ENGINE_NAME_AND_VER);
|
||||||
|
|
||||||
#if defined(USE_SDL2)
|
#if defined(USE_SDL2)
|
||||||
/* Create the window if needed, hidden */
|
/* Create the window if needed, hidden */
|
||||||
|
@ -617,6 +617,8 @@ static qboolean VID_SetMode (int width, int height, int refreshrate, int bpp, qb
|
||||||
|
|
||||||
if (vid_borderless.value)
|
if (vid_borderless.value)
|
||||||
flags |= SDL_WINDOW_BORDERLESS;
|
flags |= SDL_WINDOW_BORDERLESS;
|
||||||
|
else if (!fullscreen)
|
||||||
|
flags |= SDL_WINDOW_RESIZABLE;
|
||||||
|
|
||||||
draw_context = SDL_CreateWindow (caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
|
draw_context = SDL_CreateWindow (caption, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
|
||||||
if (!draw_context) { // scale back fsaa
|
if (!draw_context) { // scale back fsaa
|
||||||
|
@ -1290,10 +1292,11 @@ static void GL_SetupState (void)
|
||||||
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //johnfitz
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //johnfitz
|
||||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
//spike -- these are invalid as there is no texture bound to receive this state.
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
glDepthRange (0, 1); //johnfitz -- moved here becuase gl_ztrick is gone.
|
glDepthRange (0, 1); //johnfitz -- moved here becuase gl_ztrick is gone.
|
||||||
glDepthFunc (GL_LEQUAL); //johnfitz -- moved here becuase gl_ztrick is gone.
|
glDepthFunc (GL_LEQUAL); //johnfitz -- moved here becuase gl_ztrick is gone.
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,35 @@ typedef struct particle_s
|
||||||
ptype_t type;
|
ptype_t type;
|
||||||
} particle_t;
|
} particle_t;
|
||||||
|
|
||||||
|
#define P_INVALID -1
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
void PScript_InitParticles (void);
|
||||||
|
void PScript_Shutdown (void);
|
||||||
|
void PScript_DrawParticles (void);
|
||||||
|
struct trailstate_s;
|
||||||
|
int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t axis[3], struct trailstate_s **tsk);
|
||||||
|
int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, int typenum, struct trailstate_s **tsk);
|
||||||
|
void PScript_RunParticleWeather(vec3_t minb, vec3_t maxb, vec3_t dir, float count, int colour, const char *efname);
|
||||||
|
void PScript_EmitSkyEffectTris(qmodel_t *mod, msurface_t *fa, int ptype);
|
||||||
|
int PScript_FindParticleType(const char *fullname);
|
||||||
|
int PScript_RunParticleEffectTypeString (vec3_t org, vec3_t dir, float count, const char *name);
|
||||||
|
int PScript_EntParticleTrail(vec3_t oldorg, entity_t *ent, const char *name);
|
||||||
|
int PScript_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);
|
||||||
|
void PScript_DelinkTrailstate(struct trailstate_s **tsk);
|
||||||
|
void PScript_ClearParticles (void);
|
||||||
|
void PScript_UpdateModelEffects(qmodel_t *mod);
|
||||||
|
void PScript_ClearSurfaceParticles(qmodel_t *mod); //model is being unloaded.
|
||||||
|
#else
|
||||||
|
#define PScript_RunParticleEffectState(o,d,c,t,s) true
|
||||||
|
#define PScript_RunParticleEffectTypeString(o,d,c,n) true //just unconditionally returns an error
|
||||||
|
#define PScript_EntParticleTrail(o,e,n) true
|
||||||
|
#define PScript_ParticleTrail(o,e,t,d,a,s) true
|
||||||
|
#define PScript_EntParticleTrail(o,e,n) true
|
||||||
|
#define PScript_RunParticleEffect(o,d,p,c) true
|
||||||
|
#define PScript_RunParticleWeather(min,max,d,c,p,n) true
|
||||||
|
#define PScript_ClearSurfaceParticles(m)
|
||||||
|
#define PScript_DelinkTrailstate(tsp)
|
||||||
|
#endif
|
||||||
|
|
||||||
//====================================================
|
//====================================================
|
||||||
|
|
||||||
|
@ -283,7 +312,6 @@ extern devstats_t dev_stats, dev_peakstats;
|
||||||
//ohnfitz -- reduce overflow warning spam
|
//ohnfitz -- reduce overflow warning spam
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double packetsize;
|
double packetsize;
|
||||||
double efrags;
|
|
||||||
double beams;
|
double beams;
|
||||||
double varstring;
|
double varstring;
|
||||||
} overflowtimes_t;
|
} overflowtimes_t;
|
||||||
|
@ -323,6 +351,7 @@ typedef struct glsl_attrib_binding_s {
|
||||||
} glsl_attrib_binding_t;
|
} glsl_attrib_binding_t;
|
||||||
|
|
||||||
extern float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha; //ericw
|
extern float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha; //ericw
|
||||||
|
extern float map_fallbackalpha; //spike -- because we might want r_wateralpha to apply to teleporters while water itself wasn't watervised
|
||||||
|
|
||||||
//johnfitz -- fog functions called from outside gl_fog.c
|
//johnfitz -- fog functions called from outside gl_fog.c
|
||||||
void Fog_ParseServerMessage (void);
|
void Fog_ParseServerMessage (void);
|
||||||
|
@ -336,6 +365,7 @@ void Fog_SetupFrame (void);
|
||||||
void Fog_NewMap (void);
|
void Fog_NewMap (void);
|
||||||
void Fog_Init (void);
|
void Fog_Init (void);
|
||||||
void Fog_SetupState (void);
|
void Fog_SetupState (void);
|
||||||
|
const char *Fog_GetFogCommand(void); //for demo recording
|
||||||
|
|
||||||
void R_NewGame (void);
|
void R_NewGame (void);
|
||||||
|
|
||||||
|
@ -345,7 +375,7 @@ void R_CullSurfaces (void);
|
||||||
qboolean R_CullBox (vec3_t emins, vec3_t emaxs);
|
qboolean R_CullBox (vec3_t emins, vec3_t emaxs);
|
||||||
void R_StoreEfrags (efrag_t **ppefrag);
|
void R_StoreEfrags (efrag_t **ppefrag);
|
||||||
qboolean R_CullModelForEntity (entity_t *e);
|
qboolean R_CullModelForEntity (entity_t *e);
|
||||||
void R_RotateForEntity (vec3_t origin, vec3_t angles);
|
void R_RotateForEntity (vec3_t origin, vec3_t angles, unsigned char scale);
|
||||||
void R_MarkLights (dlight_t *light, int num, mnode_t *node);
|
void R_MarkLights (dlight_t *light, int num, mnode_t *node);
|
||||||
|
|
||||||
void R_InitParticles (void);
|
void R_InitParticles (void);
|
||||||
|
@ -370,13 +400,14 @@ void GL_DeleteBModelVertexBuffer (void);
|
||||||
void GL_BuildBModelVertexBuffer (void);
|
void GL_BuildBModelVertexBuffer (void);
|
||||||
void GLMesh_LoadVertexBuffers (void);
|
void GLMesh_LoadVertexBuffers (void);
|
||||||
void GLMesh_DeleteVertexBuffers (void);
|
void GLMesh_DeleteVertexBuffers (void);
|
||||||
|
void GLMesh_LoadVertexBuffer (qmodel_t *m, aliashdr_t *hdr);
|
||||||
void R_RebuildAllLightmaps (void);
|
void R_RebuildAllLightmaps (void);
|
||||||
|
|
||||||
int R_LightPoint (vec3_t p);
|
int R_LightPoint (vec3_t p);
|
||||||
|
|
||||||
void GL_SubdivideSurface (msurface_t *fa);
|
void GL_SubdivideSurface (msurface_t *fa);
|
||||||
void R_BuildLightMap (msurface_t *surf, byte *dest, int stride);
|
void R_BuildLightMap (qmodel_t *model, msurface_t *surf, byte *dest, int stride);
|
||||||
void R_RenderDynamicLightmaps (msurface_t *fa);
|
void R_RenderDynamicLightmaps (qmodel_t *model, msurface_t *fa);
|
||||||
void R_UploadLightmaps (void);
|
void R_UploadLightmaps (void);
|
||||||
|
|
||||||
void R_DrawWorld_ShowTris (void);
|
void R_DrawWorld_ShowTris (void);
|
||||||
|
|
46
Quake/host.c
46
Quake/host.c
|
@ -61,7 +61,7 @@ cvar_t host_framerate = {"host_framerate","0",CVAR_NONE}; // set for slow motion
|
||||||
cvar_t host_speeds = {"host_speeds","0",CVAR_NONE}; // set for running times
|
cvar_t host_speeds = {"host_speeds","0",CVAR_NONE}; // set for running times
|
||||||
cvar_t host_maxfps = {"host_maxfps", "72", CVAR_ARCHIVE}; //johnfitz
|
cvar_t host_maxfps = {"host_maxfps", "72", CVAR_ARCHIVE}; //johnfitz
|
||||||
cvar_t host_timescale = {"host_timescale", "0", CVAR_NONE}; //johnfitz
|
cvar_t host_timescale = {"host_timescale", "0", CVAR_NONE}; //johnfitz
|
||||||
cvar_t max_edicts = {"max_edicts", "8192", CVAR_NONE}; //johnfitz //ericw -- changed from 2048 to 8192, removed CVAR_ARCHIVE
|
cvar_t max_edicts = {"max_edicts", "15000", CVAR_NONE}; //johnfitz //ericw -- changed from 2048 to 8192, removed CVAR_ARCHIVE
|
||||||
|
|
||||||
cvar_t sys_ticrate = {"sys_ticrate","0.05",CVAR_NONE}; // dedicated server
|
cvar_t sys_ticrate = {"sys_ticrate","0.05",CVAR_NONE}; // dedicated server
|
||||||
cvar_t serverprofile = {"serverprofile","0",CVAR_NONE};
|
cvar_t serverprofile = {"serverprofile","0",CVAR_NONE};
|
||||||
|
@ -162,6 +162,8 @@ void Host_Error (const char *error, ...)
|
||||||
va_end (argptr);
|
va_end (argptr);
|
||||||
Con_Printf ("Host_Error: %s\n",string);
|
Con_Printf ("Host_Error: %s\n",string);
|
||||||
|
|
||||||
|
Con_Redirect(NULL);
|
||||||
|
|
||||||
if (sv.active)
|
if (sv.active)
|
||||||
Host_ShutdownServer (false);
|
Host_ShutdownServer (false);
|
||||||
|
|
||||||
|
@ -434,16 +436,22 @@ void SV_DropClient (qboolean crash)
|
||||||
NET_Close (host_client->netconnection);
|
NET_Close (host_client->netconnection);
|
||||||
host_client->netconnection = NULL;
|
host_client->netconnection = NULL;
|
||||||
|
|
||||||
|
SVFTE_DestroyFrames(host_client); //release any delta state
|
||||||
|
|
||||||
// free the client (the body stays around)
|
// free the client (the body stays around)
|
||||||
host_client->active = false;
|
host_client->active = false;
|
||||||
host_client->name[0] = 0;
|
host_client->name[0] = 0;
|
||||||
host_client->old_frags = -999999;
|
host_client->old_frags = -999999;
|
||||||
net_activeconnections--;
|
net_activeconnections--;
|
||||||
|
|
||||||
|
if (host_client->download.file)
|
||||||
|
fclose(host_client->download.file);
|
||||||
|
memset(&host_client->download, 0, sizeof(host_client->download));
|
||||||
|
|
||||||
// send notification to all clients
|
// send notification to all clients
|
||||||
for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++)
|
for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++)
|
||||||
{
|
{
|
||||||
if (!client->active)
|
if (!client->knowntoqc)
|
||||||
continue;
|
continue;
|
||||||
MSG_WriteByte (&client->message, svc_updatename);
|
MSG_WriteByte (&client->message, svc_updatename);
|
||||||
MSG_WriteByte (&client->message, host_client - svs.clients);
|
MSG_WriteByte (&client->message, host_client - svs.clients);
|
||||||
|
@ -488,7 +496,7 @@ void Host_ShutdownServer(qboolean crash)
|
||||||
count = 0;
|
count = 0;
|
||||||
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
||||||
{
|
{
|
||||||
if (host_client->active && host_client->message.cursize)
|
if (host_client->active && host_client->message.cursize && host_client->netconnection)
|
||||||
{
|
{
|
||||||
if (NET_CanSendMessage (host_client->netconnection))
|
if (NET_CanSendMessage (host_client->netconnection))
|
||||||
{
|
{
|
||||||
|
@ -520,6 +528,8 @@ void Host_ShutdownServer(qboolean crash)
|
||||||
if (host_client->active)
|
if (host_client->active)
|
||||||
SV_DropClient(crash);
|
SV_DropClient(crash);
|
||||||
|
|
||||||
|
sv.worldmodel = NULL;
|
||||||
|
|
||||||
//
|
//
|
||||||
// clear structures
|
// clear structures
|
||||||
//
|
//
|
||||||
|
@ -545,6 +555,9 @@ void Host_ClearMemory (void)
|
||||||
Hunk_FreeToLowMark (host_hunklevel);
|
Hunk_FreeToLowMark (host_hunklevel);
|
||||||
cls.signon = 0;
|
cls.signon = 0;
|
||||||
free(sv.edicts); // ericw -- sv.edicts switched to use malloc()
|
free(sv.edicts); // ericw -- sv.edicts switched to use malloc()
|
||||||
|
free(cl.static_entities);
|
||||||
|
free(sv.static_entities); //spike -- this is dynamic too, now
|
||||||
|
free(sv.ambientsounds);
|
||||||
memset (&sv, 0, sizeof(sv));
|
memset (&sv, 0, sizeof(sv));
|
||||||
memset (&cl, 0, sizeof(cl));
|
memset (&cl, 0, sizeof(cl));
|
||||||
}
|
}
|
||||||
|
@ -571,7 +584,7 @@ qboolean Host_FilterTime (float time)
|
||||||
|
|
||||||
//johnfitz -- max fps cvar
|
//johnfitz -- max fps cvar
|
||||||
maxfps = CLAMP (10.0, host_maxfps.value, 1000.0);
|
maxfps = CLAMP (10.0, host_maxfps.value, 1000.0);
|
||||||
if (!cls.timedemo && realtime - oldrealtime < 1.0/maxfps)
|
if (host_maxfps.value && !cls.timedemo && realtime - oldrealtime < 1.0/maxfps)
|
||||||
return false; // framerate is too high
|
return false; // framerate is too high
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
|
||||||
|
@ -584,7 +597,7 @@ qboolean Host_FilterTime (float time)
|
||||||
//johnfitz
|
//johnfitz
|
||||||
else if (host_framerate.value > 0)
|
else if (host_framerate.value > 0)
|
||||||
host_frametime = host_framerate.value;
|
host_frametime = host_framerate.value;
|
||||||
else // don't allow really long or short frames
|
else if (host_maxfps.value)// don't allow really long or short frames
|
||||||
host_frametime = CLAMP (0.001, host_frametime, 0.1); //johnfitz -- use CLAMP
|
host_frametime = CLAMP (0.001, host_frametime, 0.1); //johnfitz -- use CLAMP
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -697,6 +710,18 @@ void _Host_Frame (float time)
|
||||||
|
|
||||||
NET_Poll();
|
NET_Poll();
|
||||||
|
|
||||||
|
if (cl.sendprespawn)
|
||||||
|
{
|
||||||
|
if (CL_CheckDownloads())
|
||||||
|
{
|
||||||
|
cl.sendprespawn = false;
|
||||||
|
MSG_WriteByte (&cls.message, clc_stringcmd);
|
||||||
|
MSG_WriteString (&cls.message, "prespawn");
|
||||||
|
}
|
||||||
|
else if (!cls.message.cursize)
|
||||||
|
MSG_WriteByte (&cls.message, clc_nop);
|
||||||
|
}
|
||||||
|
|
||||||
// if running the server locally, make intentions now
|
// if running the server locally, make intentions now
|
||||||
if (sv.active)
|
if (sv.active)
|
||||||
CL_SendCmd ();
|
CL_SendCmd ();
|
||||||
|
@ -874,8 +899,13 @@ void Host_Init (void)
|
||||||
host_initialized = true;
|
host_initialized = true;
|
||||||
Con_Printf ("\n========= Quake Initialized =========\n\n");
|
Con_Printf ("\n========= Quake Initialized =========\n\n");
|
||||||
|
|
||||||
|
//spike -- create these aliases, because they're useful.
|
||||||
|
Cbuf_AddText ("alias startmap_sp \"map start\"\n");
|
||||||
|
Cbuf_AddText ("alias startmap_dm \"map start\"\n");
|
||||||
|
|
||||||
if (cls.state != ca_dedicated)
|
if (cls.state != ca_dedicated)
|
||||||
{
|
{
|
||||||
|
Cbuf_AddText ("cl_warncmd 0\n");
|
||||||
Cbuf_InsertText ("exec quake.rc\n");
|
Cbuf_InsertText ("exec quake.rc\n");
|
||||||
// johnfitz -- in case the vid mode was locked during vid_init, we can unlock it now.
|
// johnfitz -- in case the vid mode was locked during vid_init, we can unlock it now.
|
||||||
// note: two leading newlines because the command buffer swallows one of them.
|
// note: two leading newlines because the command buffer swallows one of them.
|
||||||
|
@ -884,11 +914,15 @@ void Host_Init (void)
|
||||||
|
|
||||||
if (cls.state == ca_dedicated)
|
if (cls.state == ca_dedicated)
|
||||||
{
|
{
|
||||||
|
Cbuf_AddText ("cl_warncmd 0\n");
|
||||||
|
Cbuf_AddText ("exec default.cfg\n"); //spike -- someone decided that quake.rc shouldn't be execed on dedicated servers, but that means you'll get bad defaults
|
||||||
|
Cbuf_AddText ("cl_warncmd 1\n");
|
||||||
|
Cbuf_AddText ("exec server.cfg\n"); //spike -- for people who want things explicit.
|
||||||
Cbuf_AddText ("exec autoexec.cfg\n");
|
Cbuf_AddText ("exec autoexec.cfg\n");
|
||||||
Cbuf_AddText ("stuffcmds");
|
Cbuf_AddText ("stuffcmds");
|
||||||
Cbuf_Execute ();
|
Cbuf_Execute ();
|
||||||
if (!sv.active)
|
if (!sv.active)
|
||||||
Cbuf_AddText ("map start\n");
|
Cbuf_AddText ("startmap_dm\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
536
Quake/host_cmd.c
536
Quake/host_cmd.c
|
@ -427,7 +427,7 @@ void Host_Status_f (void)
|
||||||
int seconds;
|
int seconds;
|
||||||
int minutes;
|
int minutes;
|
||||||
int hours = 0;
|
int hours = 0;
|
||||||
int j;
|
int j, i;
|
||||||
|
|
||||||
if (cmd_source == src_command)
|
if (cmd_source == src_command)
|
||||||
{
|
{
|
||||||
|
@ -441,19 +441,43 @@ void Host_Status_f (void)
|
||||||
else
|
else
|
||||||
print_fn = SV_ClientPrintf;
|
print_fn = SV_ClientPrintf;
|
||||||
|
|
||||||
print_fn ("host: %s\n", Cvar_VariableString ("hostname"));
|
print_fn ( "host: %s\n", Cvar_VariableString ("hostname"));
|
||||||
print_fn ("version: %4.2f\n", VERSION);
|
print_fn ( "version: "ENGINE_NAME_AND_VER"\n");
|
||||||
if (tcpipAvailable)
|
if (ipv4Available)
|
||||||
print_fn ("tcp/ip: %s\n", my_tcpip_address);
|
print_fn ("tcp/ip: %s\n", my_ipv4_address); //Spike -- FIXME: we should really have ports displayed here or something
|
||||||
|
if (ipv6Available)
|
||||||
|
print_fn ("ipv6: %s\n", my_ipv6_address);
|
||||||
if (ipxAvailable)
|
if (ipxAvailable)
|
||||||
print_fn ("ipx: %s\n", my_ipx_address);
|
print_fn ("ipx: %s\n", my_ipx_address);
|
||||||
print_fn ("map: %s\n", sv.name);
|
print_fn ( "map: %s\n", sv.name);
|
||||||
print_fn ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients);
|
|
||||||
|
for (i = 1,j=0; i < MAX_MODELS; i++)
|
||||||
|
if (sv.model_precache[i])
|
||||||
|
j++;
|
||||||
|
print_fn ( "models: %i/%i\n", j, MAX_MODELS-1);
|
||||||
|
for (i = 1,j=0; i < MAX_SOUNDS; i++)
|
||||||
|
if (sv.sound_precache[i])
|
||||||
|
j++;
|
||||||
|
print_fn ( "sounds: %i/%i\n", j, MAX_SOUNDS-1);
|
||||||
|
for (i = 0,j=0; i < MAX_PARTICLETYPES; i++)
|
||||||
|
if (sv.particle_precache[i])
|
||||||
|
j++;
|
||||||
|
if (j)
|
||||||
|
print_fn ( "effects: %i/%i\n", j, MAX_PARTICLETYPES-1);
|
||||||
|
for (i = 1,j=1; i < sv.num_edicts; i++)
|
||||||
|
if (!sv.edicts[i].free)
|
||||||
|
j++;
|
||||||
|
print_fn ( "entities:%i/%i\n", j, sv.max_edicts);
|
||||||
|
|
||||||
|
print_fn ( "players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients);
|
||||||
for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
|
for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
|
||||||
{
|
{
|
||||||
if (!client->active)
|
if (!client->active)
|
||||||
continue;
|
continue;
|
||||||
seconds = (int)(net_time - NET_QSocketGetTime(client->netconnection));
|
if (client->netconnection)
|
||||||
|
seconds = (int)(net_time - NET_QSocketGetTime(client->netconnection));
|
||||||
|
else
|
||||||
|
seconds = 0;
|
||||||
minutes = seconds / 60;
|
minutes = seconds / 60;
|
||||||
if (minutes)
|
if (minutes)
|
||||||
{
|
{
|
||||||
|
@ -465,7 +489,10 @@ void Host_Status_f (void)
|
||||||
else
|
else
|
||||||
hours = 0;
|
hours = 0;
|
||||||
print_fn ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds);
|
print_fn ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds);
|
||||||
print_fn (" %s\n", NET_QSocketGetAddressString(client->netconnection));
|
if (cmd_source == src_command)
|
||||||
|
print_fn (" %s\n", client->netconnection?NET_QSocketGetTrueAddressString(client->netconnection):"botclient");
|
||||||
|
else
|
||||||
|
print_fn (" %s\n", client->netconnection?NET_QSocketGetMaskedAddressString(client->netconnection):"botclient");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,7 +779,7 @@ void Host_Ping_f (void)
|
||||||
SV_ClientPrintf ("Client ping times:\n");
|
SV_ClientPrintf ("Client ping times:\n");
|
||||||
for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++)
|
for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++)
|
||||||
{
|
{
|
||||||
if (!client->active)
|
if (!client->spawned || !client->netconnection)
|
||||||
continue;
|
continue;
|
||||||
total = 0;
|
total = 0;
|
||||||
for (j = 0; j < NUM_PING_TIMES; j++)
|
for (j = 0; j < NUM_PING_TIMES; j++)
|
||||||
|
@ -928,11 +955,16 @@ void Host_Restart_f (void)
|
||||||
{
|
{
|
||||||
char mapname[MAX_QPATH];
|
char mapname[MAX_QPATH];
|
||||||
|
|
||||||
if (cls.demoplayback || !sv.active)
|
if (cls.demoplayback)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (cmd_source != src_command)
|
if (cmd_source != src_command)
|
||||||
return;
|
return;
|
||||||
|
if (!sv.active)
|
||||||
|
{
|
||||||
|
if (*sv.name)
|
||||||
|
Cmd_ExecuteString(va("map \"%s\"\n", sv.name), src_command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
q_strlcpy (mapname, sv.name, sizeof(mapname)); // mapname gets cleared in spawnserver
|
q_strlcpy (mapname, sv.name, sizeof(mapname)); // mapname gets cleared in spawnserver
|
||||||
SV_SpawnServer (mapname);
|
SV_SpawnServer (mapname);
|
||||||
if (!sv.active)
|
if (!sv.active)
|
||||||
|
@ -945,14 +977,28 @@ Host_Reconnect_f
|
||||||
|
|
||||||
This command causes the client to wait for the signon messages again.
|
This command causes the client to wait for the signon messages again.
|
||||||
This is sent just before a server changes levels
|
This is sent just before a server changes levels
|
||||||
|
|
||||||
|
for compatibility with quakeworld et al, we also allow this as a user-command to reconnect to the last server we tried, but we can only reliably do that when we're not already connected
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
void Host_Reconnect_f (void)
|
void Host_Reconnect_Con_f (void)
|
||||||
|
{
|
||||||
|
CL_Disconnect_f();
|
||||||
|
cls.demonum = -1; // stop demo loop in case this fails
|
||||||
|
if (cls.demoplayback)
|
||||||
|
{
|
||||||
|
CL_StopPlayback ();
|
||||||
|
CL_Disconnect ();
|
||||||
|
}
|
||||||
|
CL_EstablishConnection (NULL);
|
||||||
|
}
|
||||||
|
void Host_Reconnect_Sv_f (void)
|
||||||
{
|
{
|
||||||
if (cls.demoplayback) // cross-map demo playback fix from Baker
|
if (cls.demoplayback) // cross-map demo playback fix from Baker
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SCR_BeginLoadingPlaque ();
|
SCR_BeginLoadingPlaque ();
|
||||||
|
cl.protocol_dpdownload = false;
|
||||||
cls.signon = 0; // need new connection messages
|
cls.signon = 0; // need new connection messages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,7 +1021,7 @@ void Host_Connect_f (void)
|
||||||
}
|
}
|
||||||
q_strlcpy (name, Cmd_Argv(1), sizeof(name));
|
q_strlcpy (name, Cmd_Argv(1), sizeof(name));
|
||||||
CL_EstablishConnection (name);
|
CL_EstablishConnection (name);
|
||||||
Host_Reconnect_f ();
|
Host_Reconnect_Sv_f ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1092,7 +1138,7 @@ void Host_Savegame_f (void)
|
||||||
|
|
||||||
// write the light styles
|
// write the light styles
|
||||||
|
|
||||||
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
for (i = 0; i < MAX_LIGHTSTYLES_VANILLA; i++)
|
||||||
{
|
{
|
||||||
if (sv.lightstyles[i])
|
if (sv.lightstyles[i])
|
||||||
fprintf (f, "%s\n", sv.lightstyles[i]);
|
fprintf (f, "%s\n", sv.lightstyles[i]);
|
||||||
|
@ -1107,6 +1153,37 @@ void Host_Savegame_f (void)
|
||||||
ED_Write (f, EDICT_NUM(i));
|
ED_Write (f, EDICT_NUM(i));
|
||||||
fflush (f);
|
fflush (f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//add extra info (lightstyles, precaches, etc) in a way that's supposed to be compatible with DP.
|
||||||
|
//sidenote - this provides extended lightstyles and support for late precaches
|
||||||
|
//it does NOT protect against spawnfunc precache changes - we would need to include makestatics here too (and optionally baselines, or just recalculate those).
|
||||||
|
fprintf(f, "/*\n");
|
||||||
|
fprintf(f, "// QuakeSpasm extended savegame\n");
|
||||||
|
for (i = MAX_LIGHTSTYLES_VANILLA; i < MAX_LIGHTSTYLES; i++)
|
||||||
|
{
|
||||||
|
if (sv.lightstyles[i])
|
||||||
|
fprintf (f, "sv.lightstyles %i \"%s\"\n", i, sv.lightstyles[i]);
|
||||||
|
else
|
||||||
|
fprintf (f, "sv.lightstyles %i \"\"\n", i);
|
||||||
|
}
|
||||||
|
for (i = 1; i < MAX_MODELS; i++)
|
||||||
|
{
|
||||||
|
if (sv.model_precache[i])
|
||||||
|
fprintf (f, "sv.model_precache %i \"%s\"\n", i, sv.model_precache[i]);
|
||||||
|
}
|
||||||
|
for (i = 1; i < MAX_SOUNDS; i++)
|
||||||
|
{
|
||||||
|
if (sv.sound_precache[i])
|
||||||
|
fprintf (f, "sv.sound_precache %i \"%s\"\n", i, sv.sound_precache[i]);
|
||||||
|
}
|
||||||
|
for (i = 1; i < MAX_PARTICLETYPES; i++)
|
||||||
|
{
|
||||||
|
if (sv.particle_precache[i])
|
||||||
|
fprintf (f, "sv.particle_precache %i \"%s\"\n", i, sv.particle_precache[i]);
|
||||||
|
}
|
||||||
|
fprintf(f, "*/\n");
|
||||||
|
|
||||||
|
|
||||||
fclose (f);
|
fclose (f);
|
||||||
Con_Printf ("done.\n");
|
Con_Printf ("done.\n");
|
||||||
}
|
}
|
||||||
|
@ -1205,7 +1282,7 @@ void Host_Loadgame_f (void)
|
||||||
|
|
||||||
// load the light styles
|
// load the light styles
|
||||||
|
|
||||||
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
for (i = 0; i < MAX_LIGHTSTYLES_VANILLA; i++)
|
||||||
{
|
{
|
||||||
data = COM_ParseStringNewline (data);
|
data = COM_ParseStringNewline (data);
|
||||||
sv.lightstyles[i] = (const char *)Hunk_Strdup (com_token, "lightstyles");
|
sv.lightstyles[i] = (const char *)Hunk_Strdup (com_token, "lightstyles");
|
||||||
|
@ -1215,7 +1292,69 @@ void Host_Loadgame_f (void)
|
||||||
entnum = -1; // -1 is the globals
|
entnum = -1; // -1 is the globals
|
||||||
while (*data)
|
while (*data)
|
||||||
{
|
{
|
||||||
data = COM_Parse (data);
|
while (*data == ' ' || *data == '\r' || *data == '\n')
|
||||||
|
data++;
|
||||||
|
if (data[0] == '/' && data[1] == '*' && (data[2] == '\r' || data[2] == '\n'))
|
||||||
|
{ //looks like an extended saved game
|
||||||
|
char *end;
|
||||||
|
const char *ext;
|
||||||
|
ext = data+2;
|
||||||
|
while ((end = strchr(ext, '\n')))
|
||||||
|
{
|
||||||
|
*end = 0;
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
if (!strcmp(com_token, "sv.lightstyles"))
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
idx = atoi(com_token);
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
if (idx >= 0 && idx < MAX_LIGHTSTYLES)
|
||||||
|
{
|
||||||
|
if (*com_token)
|
||||||
|
sv.lightstyles[idx] = (const char *)Hunk_Strdup (com_token, "lightstyles");
|
||||||
|
else
|
||||||
|
sv.lightstyles[idx] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "sv.model_precache"))
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
idx = atoi(com_token);
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
if (idx >= 1 && idx < MAX_MODELS)
|
||||||
|
{
|
||||||
|
sv.model_precache[idx] = (const char *)Hunk_Strdup (com_token, "model_precache");
|
||||||
|
sv.models[idx] = Mod_ForName (sv.model_precache[idx], idx==1);
|
||||||
|
//if (idx == 1)
|
||||||
|
// sv.worldmodel = sv.models[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "sv.sound_precache"))
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
idx = atoi(com_token);
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
if (idx >= 1 && idx < MAX_MODELS)
|
||||||
|
sv.sound_precache[idx] = (const char *)Hunk_Strdup (com_token, "sound_precache");
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "sv.particle_precache"))
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
idx = atoi(com_token);
|
||||||
|
ext = COM_Parse(ext);
|
||||||
|
if (idx >= 1 && idx < MAX_PARTICLETYPES)
|
||||||
|
sv.particle_precache[idx] = (const char *)Hunk_Strdup (com_token, "particle_precache");
|
||||||
|
}
|
||||||
|
*end = '\n';
|
||||||
|
ext = end+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data = COM_Parse(data);
|
||||||
if (!com_token[0])
|
if (!com_token[0])
|
||||||
break; // end of file
|
break; // end of file
|
||||||
if (strcmp(com_token,"{"))
|
if (strcmp(com_token,"{"))
|
||||||
|
@ -1259,7 +1398,7 @@ void Host_Loadgame_f (void)
|
||||||
if (cls.state != ca_dedicated)
|
if (cls.state != ca_dedicated)
|
||||||
{
|
{
|
||||||
CL_EstablishConnection ("local");
|
CL_EstablishConnection ("local");
|
||||||
Host_Reconnect_f ();
|
Host_Reconnect_Sv_f ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1604,10 +1743,9 @@ void Host_PreSpawn_f (void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize);
|
//will start splurging out prespawn data
|
||||||
MSG_WriteByte (&host_client->message, svc_signonnum);
|
host_client->sendsignon = 2;
|
||||||
MSG_WriteByte (&host_client->message, 2);
|
host_client->signonidx = 0;
|
||||||
host_client->sendsignon = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1633,6 +1771,7 @@ void Host_Spawn_f (void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
host_client->knowntoqc = true;
|
||||||
// run the entrance script
|
// run the entrance script
|
||||||
if (sv.loadgame)
|
if (sv.loadgame)
|
||||||
{ // loaded games are fully inited allready
|
{ // loaded games are fully inited allready
|
||||||
|
@ -1670,9 +1809,13 @@ void Host_Spawn_f (void)
|
||||||
// send time of update
|
// send time of update
|
||||||
MSG_WriteByte (&host_client->message, svc_time);
|
MSG_WriteByte (&host_client->message, svc_time);
|
||||||
MSG_WriteFloat (&host_client->message, sv.time);
|
MSG_WriteFloat (&host_client->message, sv.time);
|
||||||
|
if (host_client->protocol_pext2 & PEXT2_PREDINFO)
|
||||||
|
MSG_WriteShort(&host_client->message, (host_client->lastmovemessage&0xffff));
|
||||||
|
|
||||||
for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++)
|
for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++)
|
||||||
{
|
{
|
||||||
|
if (!client->knowntoqc)
|
||||||
|
continue;
|
||||||
MSG_WriteByte (&host_client->message, svc_updatename);
|
MSG_WriteByte (&host_client->message, svc_updatename);
|
||||||
MSG_WriteByte (&host_client->message, i);
|
MSG_WriteByte (&host_client->message, i);
|
||||||
MSG_WriteString (&host_client->message, client->name);
|
MSG_WriteString (&host_client->message, client->name);
|
||||||
|
@ -1687,9 +1830,13 @@ void Host_Spawn_f (void)
|
||||||
// send all current light styles
|
// send all current light styles
|
||||||
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
for (i = 0; i < MAX_LIGHTSTYLES; i++)
|
||||||
{
|
{
|
||||||
MSG_WriteByte (&host_client->message, svc_lightstyle);
|
//CL_ClearState should have cleared all lightstyles, so don't send irrelevant ones
|
||||||
MSG_WriteByte (&host_client->message, (char)i);
|
if (sv.lightstyles[i])
|
||||||
MSG_WriteString (&host_client->message, sv.lightstyles[i]);
|
{
|
||||||
|
MSG_WriteByte (&host_client->message, svc_lightstyle);
|
||||||
|
MSG_WriteByte (&host_client->message, (char)i);
|
||||||
|
MSG_WriteString (&host_client->message, sv.lightstyles[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1723,7 +1870,8 @@ void Host_Spawn_f (void)
|
||||||
MSG_WriteAngle (&host_client->message, ent->v.angles[i], sv.protocolflags );
|
MSG_WriteAngle (&host_client->message, ent->v.angles[i], sv.protocolflags );
|
||||||
MSG_WriteAngle (&host_client->message, 0, sv.protocolflags );
|
MSG_WriteAngle (&host_client->message, 0, sv.protocolflags );
|
||||||
|
|
||||||
SV_WriteClientdataToMessage (sv_player, &host_client->message);
|
if (!(host_client->protocol_pext2 & PEXT2_REPLACEMENTDELTAS))
|
||||||
|
SV_WriteClientdataToMessage (host_client, &host_client->message);
|
||||||
|
|
||||||
MSG_WriteByte (&host_client->message, svc_signonnum);
|
MSG_WriteByte (&host_client->message, svc_signonnum);
|
||||||
MSG_WriteByte (&host_client->message, 3);
|
MSG_WriteByte (&host_client->message, 3);
|
||||||
|
@ -1881,33 +2029,33 @@ void Host_Give_f (void)
|
||||||
// MED 01/04/97 added hipnotic give stuff
|
// MED 01/04/97 added hipnotic give stuff
|
||||||
if (hipnotic)
|
if (hipnotic)
|
||||||
{
|
{
|
||||||
if (t[0] == '6')
|
if (t[0] == '6')
|
||||||
{
|
{
|
||||||
if (t[1] == 'a')
|
if (t[1] == 'a')
|
||||||
sv_player->v.items = (int)sv_player->v.items | HIT_PROXIMITY_GUN;
|
sv_player->v.items = (int)sv_player->v.items | HIT_PROXIMITY_GUN;
|
||||||
else
|
else
|
||||||
sv_player->v.items = (int)sv_player->v.items | IT_GRENADE_LAUNCHER;
|
sv_player->v.items = (int)sv_player->v.items | IT_GRENADE_LAUNCHER;
|
||||||
}
|
}
|
||||||
else if (t[0] == '9')
|
else if (t[0] == '9')
|
||||||
sv_player->v.items = (int)sv_player->v.items | HIT_LASER_CANNON;
|
sv_player->v.items = (int)sv_player->v.items | HIT_LASER_CANNON;
|
||||||
else if (t[0] == '0')
|
else if (t[0] == '0')
|
||||||
sv_player->v.items = (int)sv_player->v.items | HIT_MJOLNIR;
|
sv_player->v.items = (int)sv_player->v.items | HIT_MJOLNIR;
|
||||||
else if (t[0] >= '2')
|
else if (t[0] >= '2')
|
||||||
sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
|
sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (t[0] >= '2')
|
if (t[0] >= '2')
|
||||||
sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
|
sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
if (rogue)
|
if (rogue)
|
||||||
{
|
{
|
||||||
val = GetEdictFieldValue(sv_player, "ammo_shells1");
|
val = GetEdictFieldValue(sv_player, ED_FindFieldOffset("ammo_shells1"));
|
||||||
if (val)
|
if (val)
|
||||||
val->_float = v;
|
val->_float = v;
|
||||||
}
|
}
|
||||||
sv_player->v.ammo_shells = v;
|
sv_player->v.ammo_shells = v;
|
||||||
break;
|
break;
|
||||||
|
@ -1915,60 +2063,60 @@ void Host_Give_f (void)
|
||||||
case 'n':
|
case 'n':
|
||||||
if (rogue)
|
if (rogue)
|
||||||
{
|
{
|
||||||
val = GetEdictFieldValue(sv_player, "ammo_nails1");
|
val = GetEdictFieldValue(sv_player, ED_FindFieldOffset("ammo_nails1"));
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
val->_float = v;
|
val->_float = v;
|
||||||
if (sv_player->v.weapon <= IT_LIGHTNING)
|
if (sv_player->v.weapon <= IT_LIGHTNING)
|
||||||
sv_player->v.ammo_nails = v;
|
sv_player->v.ammo_nails = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sv_player->v.ammo_nails = v;
|
sv_player->v.ammo_nails = v;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
if (rogue)
|
if (rogue)
|
||||||
{
|
{
|
||||||
val = GetEdictFieldValue(sv_player, "ammo_lava_nails");
|
val = GetEdictFieldValue(sv_player, ED_FindFieldOffset("ammo_lava_nails"));
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
val->_float = v;
|
val->_float = v;
|
||||||
if (sv_player->v.weapon > IT_LIGHTNING)
|
if (sv_player->v.weapon > IT_LIGHTNING)
|
||||||
sv_player->v.ammo_nails = v;
|
sv_player->v.ammo_nails = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
if (rogue)
|
if (rogue)
|
||||||
{
|
{
|
||||||
val = GetEdictFieldValue(sv_player, "ammo_rockets1");
|
val = GetEdictFieldValue(sv_player, ED_FindFieldOffset("ammo_rockets1"));
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
val->_float = v;
|
val->_float = v;
|
||||||
if (sv_player->v.weapon <= IT_LIGHTNING)
|
if (sv_player->v.weapon <= IT_LIGHTNING)
|
||||||
sv_player->v.ammo_rockets = v;
|
sv_player->v.ammo_rockets = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sv_player->v.ammo_rockets = v;
|
sv_player->v.ammo_rockets = v;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
if (rogue)
|
if (rogue)
|
||||||
{
|
{
|
||||||
val = GetEdictFieldValue(sv_player, "ammo_multi_rockets");
|
val = GetEdictFieldValue(sv_player, ED_FindFieldOffset("ammo_multi_rockets"));
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
val->_float = v;
|
val->_float = v;
|
||||||
if (sv_player->v.weapon > IT_LIGHTNING)
|
if (sv_player->v.weapon > IT_LIGHTNING)
|
||||||
sv_player->v.ammo_rockets = v;
|
sv_player->v.ammo_rockets = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1979,30 +2127,30 @@ void Host_Give_f (void)
|
||||||
case 'c':
|
case 'c':
|
||||||
if (rogue)
|
if (rogue)
|
||||||
{
|
{
|
||||||
val = GetEdictFieldValue(sv_player, "ammo_cells1");
|
val = GetEdictFieldValue(sv_player, ED_FindFieldOffset("ammo_cells1"));
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
val->_float = v;
|
val->_float = v;
|
||||||
if (sv_player->v.weapon <= IT_LIGHTNING)
|
if (sv_player->v.weapon <= IT_LIGHTNING)
|
||||||
sv_player->v.ammo_cells = v;
|
sv_player->v.ammo_cells = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sv_player->v.ammo_cells = v;
|
sv_player->v.ammo_cells = v;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
if (rogue)
|
if (rogue)
|
||||||
{
|
{
|
||||||
val = GetEdictFieldValue(sv_player, "ammo_plasma");
|
val = GetEdictFieldValue(sv_player, ED_FindFieldOffset("ammo_plasma"));
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
val->_float = v;
|
val->_float = v;
|
||||||
if (sv_player->v.weapon > IT_LIGHTNING)
|
if (sv_player->v.weapon > IT_LIGHTNING)
|
||||||
sv_player->v.ammo_cells = v;
|
sv_player->v.ammo_cells = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2010,25 +2158,25 @@ void Host_Give_f (void)
|
||||||
case 'a':
|
case 'a':
|
||||||
if (v > 150)
|
if (v > 150)
|
||||||
{
|
{
|
||||||
sv_player->v.armortype = 0.8;
|
sv_player->v.armortype = 0.8;
|
||||||
sv_player->v.armorvalue = v;
|
sv_player->v.armorvalue = v;
|
||||||
sv_player->v.items = sv_player->v.items -
|
sv_player->v.items = sv_player->v.items -
|
||||||
((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) +
|
((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) +
|
||||||
IT_ARMOR3;
|
IT_ARMOR3;
|
||||||
}
|
}
|
||||||
else if (v > 100)
|
else if (v > 100)
|
||||||
{
|
{
|
||||||
sv_player->v.armortype = 0.6;
|
sv_player->v.armortype = 0.6;
|
||||||
sv_player->v.armorvalue = v;
|
sv_player->v.armorvalue = v;
|
||||||
sv_player->v.items = sv_player->v.items -
|
sv_player->v.items = sv_player->v.items -
|
||||||
((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) +
|
((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) +
|
||||||
IT_ARMOR2;
|
IT_ARMOR2;
|
||||||
}
|
}
|
||||||
else if (v >= 0)
|
else if (v >= 0)
|
||||||
{
|
{
|
||||||
sv_player->v.armortype = 0.3;
|
sv_player->v.armortype = 0.3;
|
||||||
sv_player->v.armorvalue = v;
|
sv_player->v.armorvalue = v;
|
||||||
sv_player->v.items = sv_player->v.items -
|
sv_player->v.items = sv_player->v.items -
|
||||||
((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) +
|
((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) +
|
||||||
IT_ARMOR1;
|
IT_ARMOR1;
|
||||||
}
|
}
|
||||||
|
@ -2280,6 +2428,155 @@ void Host_Stopdemo_f (void)
|
||||||
CL_Disconnect ();
|
CL_Disconnect ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//download stuff
|
||||||
|
|
||||||
|
static void Host_Download_f(void)
|
||||||
|
{
|
||||||
|
const char *fname = Cmd_Argv(1);
|
||||||
|
int fsize;
|
||||||
|
if (cmd_source == src_command)
|
||||||
|
{
|
||||||
|
//FIXME: add some sort of queuing thing
|
||||||
|
// if (cls.state == ca_connected)
|
||||||
|
// Cmd_ForwardToServer ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (cmd_source == src_client)
|
||||||
|
{
|
||||||
|
if (host_client->download.file)
|
||||||
|
{ //abort the current download if the previous didn't terminate properly.
|
||||||
|
SV_ClientPrintf("cancelling previous download\n");
|
||||||
|
MSG_WriteByte (&host_client->message, svc_stufftext);
|
||||||
|
MSG_WriteString (&host_client->message, "\nstopdownload\n");
|
||||||
|
fclose(host_client->download.file);
|
||||||
|
host_client->download.file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
host_client->download.size = 0;
|
||||||
|
host_client->download.started = false;
|
||||||
|
host_client->download.sendpos = 0;
|
||||||
|
host_client->download.ackpos = 0;
|
||||||
|
|
||||||
|
fsize = -1;
|
||||||
|
if (!COM_DownloadNameOkay(fname))
|
||||||
|
SV_ClientPrintf("refusing download of %s - restricted filename\n", fname);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fsize = COM_FOpenFile(fname, &host_client->download.file, NULL);
|
||||||
|
if (!host_client->download.file)
|
||||||
|
SV_ClientPrintf("server does not have file %s\n", fname);
|
||||||
|
else if (file_from_pak)
|
||||||
|
{
|
||||||
|
SV_ClientPrintf("refusing download of %s from inside pak\n", fname);
|
||||||
|
fclose(host_client->download.file);
|
||||||
|
host_client->download.file = NULL;
|
||||||
|
}
|
||||||
|
else if (fsize < 0 || fsize > 50*1024*1024)
|
||||||
|
{
|
||||||
|
SV_ClientPrintf("refusing download of large file %s\n", fname);
|
||||||
|
fclose(host_client->download.file);
|
||||||
|
host_client->download.file = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
host_client->download.size = (unsigned int)fsize;
|
||||||
|
if (host_client->download.file)
|
||||||
|
{
|
||||||
|
host_client->download.startpos = ftell(host_client->download.file);
|
||||||
|
Con_Printf("downloading %s to %s\n", fname, host_client->name);
|
||||||
|
MSG_WriteByte (&host_client->message, svc_stufftext);
|
||||||
|
MSG_WriteString (&host_client->message, va("\ncl_downloadbegin %u \"%s\"\n", host_client->download.size, fname));
|
||||||
|
q_strlcpy(host_client->download.name, fname, sizeof(host_client->download.name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf("refusing download of %s to %s\n", fname, host_client->name);
|
||||||
|
MSG_WriteByte (&host_client->message, svc_stufftext);
|
||||||
|
MSG_WriteString (&host_client->message, "\nstopdownload\n");
|
||||||
|
}
|
||||||
|
host_client->sendsignon = true; //override any keepalive issues.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Host_StartDownload_f(void)
|
||||||
|
{
|
||||||
|
if (cmd_source != src_client)
|
||||||
|
return;
|
||||||
|
if (host_client->download.file)
|
||||||
|
host_client->download.started = true;
|
||||||
|
else
|
||||||
|
SV_ClientPrintf("no download started\n");
|
||||||
|
}
|
||||||
|
//just writes download data onto the end of the outgoing unreliable buffer
|
||||||
|
void Host_AppendDownloadData(client_t *client, sizebuf_t *buf)
|
||||||
|
{
|
||||||
|
if (buf->cursize+7 > buf->maxsize)
|
||||||
|
return; //no space for anything
|
||||||
|
if (client->download.file && client->download.started)
|
||||||
|
{
|
||||||
|
byte tbuf[1400]; //don't be too aggressive, ethernet mtu is about 1450
|
||||||
|
unsigned int size = client->download.size - client->download.sendpos;
|
||||||
|
//size might be 0 at eof, and that's needed to avoid failure if we drop the last few packets
|
||||||
|
if (size > sizeof(tbuf))
|
||||||
|
size = sizeof(tbuf);
|
||||||
|
if ((int)size > buf->maxsize-(buf->cursize+7))
|
||||||
|
size = (int)(buf->maxsize-(buf->cursize+7)); //don't overflow
|
||||||
|
|
||||||
|
if (size && fread(tbuf, 1, size, host_client->download.file) < size)
|
||||||
|
client->download.ackpos = client->download.sendpos = client->download.size; //some kind of error...
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MSG_WriteByte(buf, svcdp_downloaddata);
|
||||||
|
MSG_WriteLong(buf, client->download.sendpos);
|
||||||
|
MSG_WriteShort(buf, size);
|
||||||
|
SZ_Write(buf, tbuf, size);
|
||||||
|
client->download.sendpos += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//parses incoming acks from the client, so we know which parts of the file the client actually received.
|
||||||
|
void Host_DownloadAck(client_t *client)
|
||||||
|
{
|
||||||
|
unsigned int start = MSG_ReadLong();
|
||||||
|
unsigned int size = (unsigned short)MSG_ReadShort();
|
||||||
|
|
||||||
|
if (!client->download.started || !client->download.file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (client->download.ackpos < start)
|
||||||
|
{
|
||||||
|
client->download.sendpos = client->download.ackpos;//there was a gap, rewind to the known gap
|
||||||
|
fseek(client->download.file, host_client->download.startpos+client->download.sendpos, SEEK_SET);
|
||||||
|
}
|
||||||
|
else if (client->download.ackpos < start+size)
|
||||||
|
client->download.ackpos = start+size; //no loss yet.
|
||||||
|
//else FIXME: build a log of parts known to be acked to avoid resending them later, skip past them in acks
|
||||||
|
|
||||||
|
if (client->download.ackpos == client->download.size)
|
||||||
|
{
|
||||||
|
unsigned int hash = 0;
|
||||||
|
byte *data;
|
||||||
|
client->download.started = false;
|
||||||
|
|
||||||
|
data = malloc(client->download.size);
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
fseek(client->download.file, host_client->download.startpos, SEEK_SET);
|
||||||
|
fread(data, 1, host_client->download.size, client->download.file);
|
||||||
|
hash = CRC_Block(data, host_client->download.size);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
fclose(client->download.file);
|
||||||
|
client->download.file = NULL;
|
||||||
|
|
||||||
|
MSG_WriteByte (&host_client->message, svc_stufftext);
|
||||||
|
MSG_WriteString (&host_client->message, va("cl_downloadfinished %u %u \"%s\"\n", client->download.size, hash, client->download.name));
|
||||||
|
*client->download.name = 0;
|
||||||
|
host_client->sendsignon = true; //override any keepalive issues.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2295,34 +2592,37 @@ void Host_InitCommands (void)
|
||||||
Cmd_AddCommand ("mapname", Host_Mapname_f); //johnfitz
|
Cmd_AddCommand ("mapname", Host_Mapname_f); //johnfitz
|
||||||
Cmd_AddCommand ("randmap", Host_Randmap_f); //ericw
|
Cmd_AddCommand ("randmap", Host_Randmap_f); //ericw
|
||||||
|
|
||||||
Cmd_AddCommand ("status", Host_Status_f);
|
Cmd_AddCommand_ClientCommand ("status", Host_Status_f);
|
||||||
Cmd_AddCommand ("quit", Host_Quit_f);
|
Cmd_AddCommand ("quit", Host_Quit_f);
|
||||||
Cmd_AddCommand ("god", Host_God_f);
|
Cmd_AddCommand_ClientCommand ("god", Host_God_f);
|
||||||
Cmd_AddCommand ("notarget", Host_Notarget_f);
|
Cmd_AddCommand_ClientCommand ("notarget", Host_Notarget_f);
|
||||||
Cmd_AddCommand ("fly", Host_Fly_f);
|
Cmd_AddCommand_ClientCommand ("fly", Host_Fly_f);
|
||||||
Cmd_AddCommand ("map", Host_Map_f);
|
Cmd_AddCommand ("map", Host_Map_f);
|
||||||
Cmd_AddCommand ("restart", Host_Restart_f);
|
Cmd_AddCommand ("restart", Host_Restart_f);
|
||||||
Cmd_AddCommand ("changelevel", Host_Changelevel_f);
|
Cmd_AddCommand ("changelevel", Host_Changelevel_f);
|
||||||
Cmd_AddCommand ("connect", Host_Connect_f);
|
Cmd_AddCommand ("connect", Host_Connect_f);
|
||||||
Cmd_AddCommand ("reconnect", Host_Reconnect_f);
|
Cmd_AddCommand_Console ("reconnect", Host_Reconnect_Con_f);
|
||||||
Cmd_AddCommand ("name", Host_Name_f);
|
Cmd_AddCommand_ServerCommand ("reconnect", Host_Reconnect_Sv_f);
|
||||||
Cmd_AddCommand ("noclip", Host_Noclip_f);
|
Cmd_AddCommand_ClientCommand ("name", Host_Name_f);
|
||||||
Cmd_AddCommand ("setpos", Host_SetPos_f); //QuakeSpasm
|
Cmd_AddCommand_ClientCommand ("noclip", Host_Noclip_f);
|
||||||
|
Cmd_AddCommand_ClientCommand ("setpos", Host_SetPos_f); //QuakeSpasm
|
||||||
|
|
||||||
Cmd_AddCommand ("say", Host_Say_f);
|
Cmd_AddCommand_ClientCommand ("say", Host_Say_f);
|
||||||
Cmd_AddCommand ("say_team", Host_Say_Team_f);
|
Cmd_AddCommand_ClientCommand ("say_team", Host_Say_Team_f);
|
||||||
Cmd_AddCommand ("tell", Host_Tell_f);
|
Cmd_AddCommand_ClientCommand ("tell", Host_Tell_f);
|
||||||
Cmd_AddCommand ("color", Host_Color_f);
|
Cmd_AddCommand_ClientCommand ("color", Host_Color_f);
|
||||||
Cmd_AddCommand ("kill", Host_Kill_f);
|
Cmd_AddCommand_ClientCommand ("kill", Host_Kill_f);
|
||||||
Cmd_AddCommand ("pause", Host_Pause_f);
|
Cmd_AddCommand_ClientCommand ("pause", Host_Pause_f);
|
||||||
Cmd_AddCommand ("spawn", Host_Spawn_f);
|
Cmd_AddCommand_ClientCommand ("spawn", Host_Spawn_f);
|
||||||
Cmd_AddCommand ("begin", Host_Begin_f);
|
Cmd_AddCommand_ClientCommand ("begin", Host_Begin_f);
|
||||||
Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
|
Cmd_AddCommand_ClientCommand ("prespawn", Host_PreSpawn_f);
|
||||||
Cmd_AddCommand ("kick", Host_Kick_f);
|
Cmd_AddCommand_ClientCommand ("kick", Host_Kick_f);
|
||||||
Cmd_AddCommand ("ping", Host_Ping_f);
|
Cmd_AddCommand_ClientCommand ("ping", Host_Ping_f);
|
||||||
Cmd_AddCommand ("load", Host_Loadgame_f);
|
Cmd_AddCommand ("load", Host_Loadgame_f);
|
||||||
Cmd_AddCommand ("save", Host_Savegame_f);
|
Cmd_AddCommand ("save", Host_Savegame_f);
|
||||||
Cmd_AddCommand ("give", Host_Give_f);
|
Cmd_AddCommand_ClientCommand ("give", Host_Give_f);
|
||||||
|
Cmd_AddCommand_ClientCommand ("download", Host_Download_f);
|
||||||
|
Cmd_AddCommand_ClientCommand ("sv_startdownload", Host_StartDownload_f);
|
||||||
|
|
||||||
Cmd_AddCommand ("startdemos", Host_Startdemos_f);
|
Cmd_AddCommand ("startdemos", Host_Startdemos_f);
|
||||||
Cmd_AddCommand ("demos", Host_Demos_f);
|
Cmd_AddCommand ("demos", Host_Demos_f);
|
||||||
|
|
|
@ -69,6 +69,54 @@ static inline int Buf_GetC(stdio_buffer_t *buf)
|
||||||
return buf->buffer[buf->pos++];
|
return buf->buffer[buf->pos++];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*small function to read files with stb_image - single-file image loader library.
|
||||||
|
** downloaded from: https://raw.githubusercontent.com/nothings/stb/master/stb_image.h
|
||||||
|
** only use jpeg+png formats, because tbh there's not much need for the others.
|
||||||
|
** */
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STBI_ONLY_JPEG
|
||||||
|
#ifdef LODEPNG_NO_COMPILE_DECODER
|
||||||
|
#define STBI_ONLY_PNG
|
||||||
|
#endif
|
||||||
|
#include "stb_image.h"
|
||||||
|
static byte *Image_LoadSTBI(FILE *f, int *width, int *height)
|
||||||
|
{
|
||||||
|
int bytesPerPixel;
|
||||||
|
byte *heap = stbi_load_from_file(f, width, height, &bytesPerPixel, 4);
|
||||||
|
fclose(f);
|
||||||
|
if (heap)
|
||||||
|
{ //this is silly, but we do it for consistency.
|
||||||
|
//frankly, most people should be using tga-inside-pk3.
|
||||||
|
byte *hunk = Hunk_Alloc(*width**height*4);
|
||||||
|
memcpy(hunk, heap, *width**height*4);
|
||||||
|
free(heap);
|
||||||
|
return hunk;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *Image_LoadPNG(FILE *f, int *width, int *height, qboolean *malloced)
|
||||||
|
{
|
||||||
|
#ifdef LODEPNG_NO_COMPILE_DECODER
|
||||||
|
return Image_LoadSTBI (f, width, height);
|
||||||
|
#else
|
||||||
|
unsigned w, h;
|
||||||
|
unsigned char *out = NULL, *in;
|
||||||
|
size_t insize = com_filesize;
|
||||||
|
|
||||||
|
in = malloc(com_filesize);
|
||||||
|
if (!in)
|
||||||
|
return NULL;
|
||||||
|
if (com_filesize == fread(in, 1, com_filesize, f))
|
||||||
|
{
|
||||||
|
*malloced = true;
|
||||||
|
lodepng_decode32(&out, &w, &h, in, insize);
|
||||||
|
}
|
||||||
|
free(in);
|
||||||
|
return out;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
Image_LoadImage
|
Image_LoadImage
|
||||||
|
@ -78,19 +126,44 @@ returns a pointer to hunk allocated RGBA data
|
||||||
TODO: search order: tga png jpg pcx lmp
|
TODO: search order: tga png jpg pcx lmp
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
byte *Image_LoadImage (const char *name, int *width, int *height)
|
byte *Image_LoadImage (const char *name, int *width, int *height, qboolean *malloced)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
char *prefixes[3] = {"", "textures/", "textures/"};
|
||||||
|
int i;
|
||||||
|
|
||||||
q_snprintf (loadfilename, sizeof(loadfilename), "%s.tga", name);
|
*malloced = false;
|
||||||
COM_FOpenFile (loadfilename, &f, NULL);
|
|
||||||
if (f)
|
|
||||||
return Image_LoadTGA (f, width, height);
|
|
||||||
|
|
||||||
q_snprintf (loadfilename, sizeof(loadfilename), "%s.pcx", name);
|
for (i = 0; i < sizeof(prefixes)/sizeof(prefixes[0]); i++)
|
||||||
COM_FOpenFile (loadfilename, &f, NULL);
|
{
|
||||||
if (f)
|
if (i == 2) //last resort...
|
||||||
return Image_LoadPCX (f, width, height);
|
name = COM_SkipPath(name);
|
||||||
|
|
||||||
|
q_snprintf (loadfilename, sizeof(loadfilename), "%s%s.tga", prefixes[i], name);
|
||||||
|
COM_FOpenFile (loadfilename, &f, NULL);
|
||||||
|
if (f)
|
||||||
|
return Image_LoadTGA (f, width, height);
|
||||||
|
|
||||||
|
q_snprintf (loadfilename, sizeof(loadfilename), "%s%s.png", prefixes[i], name);
|
||||||
|
COM_FOpenFile (loadfilename, &f, NULL);
|
||||||
|
if (f)
|
||||||
|
return Image_LoadPNG (f, width, height, malloced);
|
||||||
|
|
||||||
|
q_snprintf (loadfilename, sizeof(loadfilename), "%s%s.jpeg", prefixes[i], name);
|
||||||
|
COM_FOpenFile (loadfilename, &f, NULL);
|
||||||
|
if (f)
|
||||||
|
return Image_LoadSTBI (f, width, height);
|
||||||
|
|
||||||
|
q_snprintf (loadfilename, sizeof(loadfilename), "%s%s.jpg", prefixes[i], name);
|
||||||
|
COM_FOpenFile (loadfilename, &f, NULL);
|
||||||
|
if (f)
|
||||||
|
return Image_LoadSTBI (f, width, height);
|
||||||
|
|
||||||
|
q_snprintf (loadfilename, sizeof(loadfilename), "%s%s.pcx", prefixes[i], name);
|
||||||
|
COM_FOpenFile (loadfilename, &f, NULL);
|
||||||
|
if (f)
|
||||||
|
return Image_LoadPCX (f, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
//be sure to free the hunk after using these loading functions
|
//be sure to free the hunk after using these loading functions
|
||||||
byte *Image_LoadTGA (FILE *f, int *width, int *height);
|
byte *Image_LoadTGA (FILE *f, int *width, int *height);
|
||||||
byte *Image_LoadPCX (FILE *f, int *width, int *height);
|
byte *Image_LoadPCX (FILE *f, int *width, int *height);
|
||||||
byte *Image_LoadImage (const char *name, int *width, int *height);
|
byte *Image_LoadImage (const char *name, int *width, int *height, qboolean *malloced);
|
||||||
|
|
||||||
qboolean Image_WriteTGA (const char *name, byte *data, int width, int height, int bpp, qboolean upsidedown);
|
qboolean Image_WriteTGA (const char *name, byte *data, int width, int height, int bpp, qboolean upsidedown);
|
||||||
qboolean Image_WritePNG (const char *name, byte *data, int width, int height, int bpp, qboolean upsidedown);
|
qboolean Image_WritePNG (const char *name, byte *data, int width, int height, int bpp, qboolean upsidedown);
|
||||||
|
|
|
@ -1014,6 +1014,12 @@ void IN_SendKeyEvents (void)
|
||||||
S_UnblockSound();
|
S_UnblockSound();
|
||||||
else if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
else if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||||
S_BlockSound();
|
S_BlockSound();
|
||||||
|
else if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
|
||||||
|
{
|
||||||
|
vid.width = event.window.data1;
|
||||||
|
vid.height = event.window.data2;
|
||||||
|
Cvar_FindVar("scr_conscale")->callback(NULL);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
case SDL_ACTIVEEVENT:
|
case SDL_ACTIVEEVENT:
|
||||||
|
|
|
@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
char key_lines[CMDLINES][MAXCMDLINE];
|
char key_lines[CMDLINES][MAXCMDLINE];
|
||||||
|
|
||||||
int key_linepos;
|
int key_linepos;
|
||||||
int key_insert; //johnfitz -- insert key toggle (for editing)
|
int key_insert = true; //johnfitz -- insert key toggle (for editing)
|
||||||
double key_blinktime; //johnfitz -- fudge cursor blinking to make it easier to spot in certain cases
|
double key_blinktime; //johnfitz -- fudge cursor blinking to make it easier to spot in certain cases
|
||||||
|
|
||||||
int edit_line = 0;
|
int edit_line = 0;
|
||||||
|
|
|
@ -136,6 +136,7 @@ int main(int argc, char *argv[])
|
||||||
Sys_Printf("FitzQuake %1.2f (c) John Fitzgibbons\n", FITZQUAKE_VERSION);
|
Sys_Printf("FitzQuake %1.2f (c) John Fitzgibbons\n", FITZQUAKE_VERSION);
|
||||||
Sys_Printf("FitzQuake SDL port (c) SleepwalkR, Baker\n");
|
Sys_Printf("FitzQuake SDL port (c) SleepwalkR, Baker\n");
|
||||||
Sys_Printf("QuakeSpasm " QUAKESPASM_VER_STRING " (c) Ozkan Sezer, Eric Wasylishen & others\n");
|
Sys_Printf("QuakeSpasm " QUAKESPASM_VER_STRING " (c) Ozkan Sezer, Eric Wasylishen & others\n");
|
||||||
|
Sys_Printf("QuakeSpasm-Spiked (c) Spike\n");
|
||||||
|
|
||||||
Sys_Printf("Host_Init\n");
|
Sys_Printf("Host_Init\n");
|
||||||
Host_Init();
|
Host_Init();
|
||||||
|
|
|
@ -211,17 +211,46 @@ int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
//johnfitz -- the opposite of AngleVectors. this takes forward and generates pitch yaw roll
|
//johnfitz -- the opposite of AngleVectors. this takes forward and generates pitch yaw roll
|
||||||
//TODO: take right and up vectors to properly set yaw and roll
|
//Spike: take right and up vectors to properly set yaw and roll
|
||||||
void VectorAngles (const vec3_t forward, vec3_t angles)
|
void VectorAngles (const vec3_t forward, float *up, vec3_t angles)
|
||||||
{
|
{
|
||||||
vec3_t temp;
|
if (forward[0] == 0 && forward[1] == 0)
|
||||||
|
{ //either vertically up or down
|
||||||
|
if (forward[2] > 0)
|
||||||
|
{
|
||||||
|
angles[PITCH] = -90;
|
||||||
|
angles[YAW] = up ? atan2(-up[1], -up[0]) / M_PI_DIV_180: 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
angles[PITCH] = 90;
|
||||||
|
angles[YAW] = up ? atan2(up[1], up[0]) / M_PI_DIV_180: 0;
|
||||||
|
}
|
||||||
|
angles[ROLL] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
angles[PITCH] = -atan2(forward[2], sqrt(DotProduct2(forward,forward)));
|
||||||
|
angles[YAW] = atan2(forward[1], forward[0]);
|
||||||
|
|
||||||
temp[0] = forward[0];
|
if (up)
|
||||||
temp[1] = forward[1];
|
{
|
||||||
temp[2] = 0;
|
vec_t cp = cos(angles[PITCH]), sp = sin(angles[PITCH]);
|
||||||
angles[PITCH] = -atan2(forward[2], VectorLength(temp)) / M_PI_DIV_180;
|
vec_t cy = cos(angles[YAW]), sy = sin(angles[YAW]);
|
||||||
angles[YAW] = atan2(forward[1], forward[0]) / M_PI_DIV_180;
|
vec3_t tleft, tup;
|
||||||
angles[ROLL] = 0;
|
tleft[0] = -sy;
|
||||||
|
tleft[1] = cy;
|
||||||
|
tleft[2] = 0;
|
||||||
|
tup[0] = sp*cy;
|
||||||
|
tup[1] = sp*sy;
|
||||||
|
tup[2] = cp;
|
||||||
|
angles[ROLL] = -atan2(DotProduct(up, tleft), DotProduct(up, tup)) / M_PI_DIV_180;
|
||||||
|
}
|
||||||
|
else angles[ROLL] = 0;
|
||||||
|
|
||||||
|
angles[PITCH] /= M_PI_DIV_180;
|
||||||
|
angles[YAW] /= M_PI_DIV_180;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
|
void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
|
||||||
|
@ -250,7 +279,7 @@ void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
|
||||||
up[2] = cr*cp;
|
up[2] = cr*cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VectorCompare (vec3_t v1, vec3_t v2)
|
int VectorCompare (const vec3_t v1, const vec3_t v2)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -261,7 +290,7 @@ int VectorCompare (vec3_t v1, vec3_t v2)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
|
void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc)
|
||||||
{
|
{
|
||||||
vecc[0] = veca[0] + scale*vecb[0];
|
vecc[0] = veca[0] + scale*vecb[0];
|
||||||
vecc[1] = veca[1] + scale*vecb[1];
|
vecc[1] = veca[1] + scale*vecb[1];
|
||||||
|
@ -269,40 +298,40 @@ void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec_t _DotProduct (vec3_t v1, vec3_t v2)
|
vec_t _DotProduct (const vec3_t v1, const vec3_t v2)
|
||||||
{
|
{
|
||||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
|
void _VectorSubtract (const vec3_t veca, const vec3_t vecb, vec3_t out)
|
||||||
{
|
{
|
||||||
out[0] = veca[0]-vecb[0];
|
out[0] = veca[0]-vecb[0];
|
||||||
out[1] = veca[1]-vecb[1];
|
out[1] = veca[1]-vecb[1];
|
||||||
out[2] = veca[2]-vecb[2];
|
out[2] = veca[2]-vecb[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
|
void _VectorAdd (const vec3_t veca, const vec3_t vecb, vec3_t out)
|
||||||
{
|
{
|
||||||
out[0] = veca[0]+vecb[0];
|
out[0] = veca[0]+vecb[0];
|
||||||
out[1] = veca[1]+vecb[1];
|
out[1] = veca[1]+vecb[1];
|
||||||
out[2] = veca[2]+vecb[2];
|
out[2] = veca[2]+vecb[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
void _VectorCopy (vec3_t in, vec3_t out)
|
void _VectorCopy (const vec3_t in, vec3_t out)
|
||||||
{
|
{
|
||||||
out[0] = in[0];
|
out[0] = in[0];
|
||||||
out[1] = in[1];
|
out[1] = in[1];
|
||||||
out[2] = in[2];
|
out[2] = in[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
|
void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross)
|
||||||
{
|
{
|
||||||
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||||
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||||
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_t VectorLength(vec3_t v)
|
vec_t VectorLength(const vec3_t v)
|
||||||
{
|
{
|
||||||
return sqrt(DotProduct(v,v));
|
return sqrt(DotProduct(v,v));
|
||||||
}
|
}
|
||||||
|
@ -332,7 +361,7 @@ void VectorInverse (vec3_t v)
|
||||||
v[2] = -v[2];
|
v[2] = -v[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorScale (vec3_t in, vec_t scale, vec3_t out)
|
void VectorScale (const vec3_t in, vec_t scale, vec3_t out)
|
||||||
{
|
{
|
||||||
out[0] = in[0]*scale;
|
out[0] = in[0]*scale;
|
||||||
out[1] = in[1]*scale;
|
out[1] = in[1]*scale;
|
||||||
|
|
|
@ -52,6 +52,7 @@ static inline int IS_NAN (float x) {
|
||||||
#define Q_rint(x) ((x) > 0 ? (int)((x) + 0.5) : (int)((x) - 0.5)) //johnfitz -- from joequake
|
#define Q_rint(x) ((x) > 0 ? (int)((x) + 0.5) : (int)((x) - 0.5)) //johnfitz -- from joequake
|
||||||
|
|
||||||
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
|
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
|
||||||
|
#define DotProduct2(x,y) (x[0]*y[0]+x[1]*y[1])
|
||||||
#define DoublePrecisionDotProduct(x,y) ((double)x[0]*y[0]+(double)x[1]*y[1]+(double)x[2]*y[2])
|
#define DoublePrecisionDotProduct(x,y) ((double)x[0]*y[0]+(double)x[1]*y[1]+(double)x[2]*y[2])
|
||||||
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
|
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
|
||||||
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
|
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
|
||||||
|
@ -72,21 +73,21 @@ static inline int IS_NAN (float x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TurnVector (vec3_t out, const vec3_t forward, const vec3_t side, float angle); //johnfitz
|
void TurnVector (vec3_t out, const vec3_t forward, const vec3_t side, float angle); //johnfitz
|
||||||
void VectorAngles (const vec3_t forward, vec3_t angles); //johnfitz
|
void VectorAngles (const vec3_t forward, float *up, vec3_t angles); //johnfitz, spike(up is optional)
|
||||||
|
|
||||||
void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
|
void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc);
|
||||||
|
|
||||||
vec_t _DotProduct (vec3_t v1, vec3_t v2);
|
vec_t _DotProduct (const vec3_t v1, const vec3_t v2);
|
||||||
void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
|
void _VectorSubtract (const vec3_t veca, const vec3_t vecb, vec3_t out);
|
||||||
void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
|
void _VectorAdd (const vec3_t veca, const vec3_t vecb, vec3_t out);
|
||||||
void _VectorCopy (vec3_t in, vec3_t out);
|
void _VectorCopy (const vec3_t in, vec3_t out);
|
||||||
|
|
||||||
int VectorCompare (vec3_t v1, vec3_t v2);
|
int VectorCompare (const vec3_t v1, const vec3_t v2);
|
||||||
vec_t VectorLength (vec3_t v);
|
vec_t VectorLength (const vec3_t v);
|
||||||
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
|
void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross);
|
||||||
float VectorNormalize (vec3_t v); // returns vector length
|
float VectorNormalize (vec3_t v); // returns vector length
|
||||||
void VectorInverse (vec3_t v);
|
void VectorInverse (vec3_t v);
|
||||||
void VectorScale (vec3_t in, vec_t scale, vec3_t out);
|
void VectorScale (const vec3_t in, vec_t scale, vec3_t out);
|
||||||
int Q_log2(int val);
|
int Q_log2(int val);
|
||||||
|
|
||||||
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
|
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
|
||||||
|
|
365
Quake/menu.c
365
Quake/menu.c
|
@ -38,7 +38,7 @@ void M_Menu_Main_f (void);
|
||||||
void M_Menu_Net_f (void);
|
void M_Menu_Net_f (void);
|
||||||
void M_Menu_LanConfig_f (void);
|
void M_Menu_LanConfig_f (void);
|
||||||
void M_Menu_GameOptions_f (void);
|
void M_Menu_GameOptions_f (void);
|
||||||
void M_Menu_Search_f (void);
|
void M_Menu_Search_f (enum slistScope_e scope);
|
||||||
void M_Menu_ServerList_f (void);
|
void M_Menu_ServerList_f (void);
|
||||||
void M_Menu_Options_f (void);
|
void M_Menu_Options_f (void);
|
||||||
void M_Menu_Keys_f (void);
|
void M_Menu_Keys_f (void);
|
||||||
|
@ -398,9 +398,10 @@ void M_SinglePlayer_Key (int key)
|
||||||
if (sv.active)
|
if (sv.active)
|
||||||
Cbuf_AddText ("disconnect\n");
|
Cbuf_AddText ("disconnect\n");
|
||||||
Cbuf_AddText ("maxplayers 1\n");
|
Cbuf_AddText ("maxplayers 1\n");
|
||||||
|
Cbuf_AddText ("samelevel 0\n"); //spike -- you'd be amazed how many qw players have this setting breaking their singleplayer experience...
|
||||||
Cbuf_AddText ("deathmatch 0\n"); //johnfitz
|
Cbuf_AddText ("deathmatch 0\n"); //johnfitz
|
||||||
Cbuf_AddText ("coop 0\n"); //johnfitz
|
Cbuf_AddText ("coop 0\n"); //johnfitz
|
||||||
Cbuf_AddText ("map start\n");
|
Cbuf_AddText ("startmap_sp\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -625,7 +626,7 @@ void M_MultiPlayer_Draw (void)
|
||||||
|
|
||||||
M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
|
M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
|
||||||
|
|
||||||
if (ipxAvailable || tcpipAvailable)
|
if (ipxAvailable || ipv4Available || ipv6Available)
|
||||||
return;
|
return;
|
||||||
M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
|
M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
|
||||||
}
|
}
|
||||||
|
@ -659,12 +660,12 @@ void M_MultiPlayer_Key (int key)
|
||||||
switch (m_multiplayer_cursor)
|
switch (m_multiplayer_cursor)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
if (ipxAvailable || tcpipAvailable)
|
if (ipxAvailable || ipv4Available || ipv6Available)
|
||||||
M_Menu_Net_f ();
|
M_Menu_Net_f ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if (ipxAvailable || tcpipAvailable)
|
if (ipxAvailable || ipv4Available || ipv6Available)
|
||||||
M_Menu_Net_f ();
|
M_Menu_Net_f ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -913,7 +914,7 @@ void M_Net_Draw (void)
|
||||||
M_DrawTransPic (72, f, p);
|
M_DrawTransPic (72, f, p);
|
||||||
|
|
||||||
f += 19;
|
f += 19;
|
||||||
if (tcpipAvailable)
|
if (ipv4Available || ipv6Available)
|
||||||
p = Draw_CachePic ("gfx/netmen4.lmp");
|
p = Draw_CachePic ("gfx/netmen4.lmp");
|
||||||
else
|
else
|
||||||
p = Draw_CachePic ("gfx/dim_tcp.lmp");
|
p = Draw_CachePic ("gfx/dim_tcp.lmp");
|
||||||
|
@ -964,7 +965,7 @@ again:
|
||||||
|
|
||||||
if (m_net_cursor == 0 && !ipxAvailable)
|
if (m_net_cursor == 0 && !ipxAvailable)
|
||||||
goto again;
|
goto again;
|
||||||
if (m_net_cursor == 1 && !tcpipAvailable)
|
if (m_net_cursor == 1 && !(ipv4Available || ipv6Available))
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1333,7 +1334,7 @@ void M_Options_Key (int k)
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
/* KEYS MENU */
|
/* KEYS MENU */
|
||||||
|
|
||||||
const char *bindnames[][2] =
|
const char *quakebindnames[][2] =
|
||||||
{
|
{
|
||||||
{"+attack", "attack"},
|
{"+attack", "attack"},
|
||||||
{"impulse 10", "next weapon"},
|
{"impulse 10", "next weapon"},
|
||||||
|
@ -1353,20 +1354,87 @@ const char *bindnames[][2] =
|
||||||
{"+mlook", "mouse look"},
|
{"+mlook", "mouse look"},
|
||||||
{"+klook", "keyboard look"},
|
{"+klook", "keyboard look"},
|
||||||
{"+moveup", "swim up"},
|
{"+moveup", "swim up"},
|
||||||
{"+movedown", "swim down"}
|
{"+movedown", "swim down"},
|
||||||
|
{"+voip", "Voice Chat"}
|
||||||
};
|
};
|
||||||
|
#define NUMQUAKECOMMANDS (sizeof(quakebindnames)/sizeof(quakebindnames[0]))
|
||||||
|
|
||||||
#define NUMCOMMANDS (sizeof(bindnames)/sizeof(bindnames[0]))
|
static struct
|
||||||
|
{
|
||||||
|
char *cmd;
|
||||||
|
char *desc;
|
||||||
|
} *bindnames;
|
||||||
|
static size_t numbindnames;
|
||||||
|
|
||||||
static int keys_cursor;
|
static size_t keys_first;
|
||||||
|
static size_t keys_cursor;
|
||||||
static qboolean bind_grab;
|
static qboolean bind_grab;
|
||||||
|
|
||||||
|
void M_Keys_Close (void)
|
||||||
|
{
|
||||||
|
while (numbindnames>0)
|
||||||
|
{
|
||||||
|
numbindnames--;
|
||||||
|
Z_Free(bindnames[numbindnames].cmd);
|
||||||
|
Z_Free(bindnames[numbindnames].desc);
|
||||||
|
}
|
||||||
|
Z_Free(bindnames);
|
||||||
|
bindnames = NULL;
|
||||||
|
numbindnames = 0;
|
||||||
|
}
|
||||||
|
void M_Keys_Populate(void)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
char line[1024];
|
||||||
|
if (numbindnames)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (COM_FOpenFile("bindlist.lst", &file, NULL) >= 0)
|
||||||
|
{
|
||||||
|
while (fgets(line, sizeof(line), file))
|
||||||
|
{
|
||||||
|
const char *cmd, *desc/*, tip*/;
|
||||||
|
Cmd_TokenizeString(line);
|
||||||
|
cmd = Cmd_Argv(0);
|
||||||
|
desc = Cmd_Argv(1);
|
||||||
|
/*tip = Cmd_Argv(2); unused in quakespasm*/
|
||||||
|
|
||||||
|
if (*cmd)
|
||||||
|
{
|
||||||
|
bindnames = Z_Realloc(bindnames, sizeof(*bindnames)*(numbindnames+1));
|
||||||
|
bindnames[numbindnames].cmd = strcpy(Z_Malloc(strlen(cmd)+1), cmd);
|
||||||
|
bindnames[numbindnames].desc = strcpy(Z_Malloc(strlen(desc)+1), desc);
|
||||||
|
numbindnames++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!numbindnames)
|
||||||
|
{
|
||||||
|
bindnames = Z_Realloc(bindnames, sizeof(*bindnames)*NUMQUAKECOMMANDS);
|
||||||
|
while(numbindnames < NUMQUAKECOMMANDS)
|
||||||
|
{
|
||||||
|
bindnames[numbindnames].cmd = strcpy(Z_Malloc(strlen(quakebindnames[numbindnames][0])+1), quakebindnames[numbindnames][0]);
|
||||||
|
bindnames[numbindnames].desc = strcpy(Z_Malloc(strlen(quakebindnames[numbindnames][1])+1), quakebindnames[numbindnames][1]);
|
||||||
|
numbindnames++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//don't start with it on text
|
||||||
|
keys_first = keys_cursor = 0;
|
||||||
|
while (keys_cursor < numbindnames-1 && !strcmp(bindnames[keys_cursor].cmd, "-"))
|
||||||
|
keys_cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
void M_Menu_Keys_f (void)
|
void M_Menu_Keys_f (void)
|
||||||
{
|
{
|
||||||
IN_Deactivate(modestate == MS_WINDOWED);
|
IN_Deactivate(modestate == MS_WINDOWED);
|
||||||
key_dest = key_menu;
|
key_dest = key_menu;
|
||||||
m_state = m_keys;
|
m_state = m_keys;
|
||||||
m_entersound = true;
|
m_entersound = true;
|
||||||
|
|
||||||
|
M_Keys_Populate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1418,10 +1486,12 @@ extern qpic_t *pic_up, *pic_down;
|
||||||
|
|
||||||
void M_Keys_Draw (void)
|
void M_Keys_Draw (void)
|
||||||
{
|
{
|
||||||
int i, x, y;
|
size_t i;
|
||||||
|
int x, y;
|
||||||
int keys[3];
|
int keys[3];
|
||||||
const char *name;
|
const char *name;
|
||||||
qpic_t *p;
|
qpic_t *p;
|
||||||
|
size_t keys_shown;
|
||||||
|
|
||||||
p = Draw_CachePic ("gfx/ttl_cstm.lmp");
|
p = Draw_CachePic ("gfx/ttl_cstm.lmp");
|
||||||
M_DrawPic ( (320-p->width)/2, 4, p);
|
M_DrawPic ( (320-p->width)/2, 4, p);
|
||||||
|
@ -1431,14 +1501,28 @@ void M_Keys_Draw (void)
|
||||||
else
|
else
|
||||||
M_Print (18, 32, "Enter to change, backspace to clear");
|
M_Print (18, 32, "Enter to change, backspace to clear");
|
||||||
|
|
||||||
|
keys_shown = numbindnames;
|
||||||
|
if (keys_shown > (200-48)/8)
|
||||||
|
keys_shown = (200-48)/8;
|
||||||
|
if (keys_first+keys_shown-1 < keys_cursor)
|
||||||
|
keys_first = keys_cursor-(keys_shown-1);
|
||||||
|
if (keys_first > keys_cursor)
|
||||||
|
keys_first = keys_cursor;
|
||||||
|
|
||||||
// search for known bindings
|
// search for known bindings
|
||||||
for (i = 0; i < (int)NUMCOMMANDS; i++)
|
for (i = keys_first; i < keys_first+keys_shown; i++)
|
||||||
{
|
{
|
||||||
y = 48 + 8*i;
|
y = 48 + 8*(i-keys_first);
|
||||||
|
|
||||||
M_Print (16, y, bindnames[i][1]);
|
if (!strcmp(bindnames[i].cmd, "-"))
|
||||||
|
{
|
||||||
|
M_PrintWhite ((320-strlen(bindnames[i].desc)*8)/2, y, bindnames[i].desc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
M_FindKeysForCommand (bindnames[i][0], keys);
|
M_Print (16, y, bindnames[i].desc);
|
||||||
|
|
||||||
|
M_FindKeysForCommand (bindnames[i].cmd, keys);
|
||||||
|
|
||||||
if (keys[0] == -1)
|
if (keys[0] == -1)
|
||||||
{
|
{
|
||||||
|
@ -1465,9 +1549,9 @@ void M_Keys_Draw (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind_grab)
|
if (bind_grab)
|
||||||
M_DrawCharacter (130, 48 + keys_cursor*8, '=');
|
M_DrawCharacter (130, 48 + (keys_cursor-keys_first)*8, '=');
|
||||||
else
|
else
|
||||||
M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
|
M_DrawCharacter (130, 48 + (keys_cursor-keys_first)*8, 12+((int)(realtime*4)&1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1481,7 +1565,7 @@ void M_Keys_Key (int k)
|
||||||
S_LocalSound ("misc/menu1.wav");
|
S_LocalSound ("misc/menu1.wav");
|
||||||
if ((k != K_ESCAPE) && (k != '`'))
|
if ((k != K_ESCAPE) && (k != '`'))
|
||||||
{
|
{
|
||||||
sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
|
sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor].cmd);
|
||||||
Cbuf_InsertText (cmd);
|
Cbuf_InsertText (cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1500,26 +1584,43 @@ void M_Keys_Key (int k)
|
||||||
case K_LEFTARROW:
|
case K_LEFTARROW:
|
||||||
case K_UPARROW:
|
case K_UPARROW:
|
||||||
S_LocalSound ("misc/menu1.wav");
|
S_LocalSound ("misc/menu1.wav");
|
||||||
keys_cursor--;
|
do
|
||||||
if (keys_cursor < 0)
|
{
|
||||||
keys_cursor = NUMCOMMANDS-1;
|
keys_cursor--;
|
||||||
|
if (keys_cursor >= numbindnames)
|
||||||
|
{
|
||||||
|
if (keys_first && strcmp(bindnames[keys_first].cmd, "-"))
|
||||||
|
{ //some weirdness, so the user can re-view any leading titles
|
||||||
|
keys_cursor = keys_first;
|
||||||
|
keys_first = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
keys_cursor = numbindnames-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (!strcmp(bindnames[keys_cursor].cmd, "-"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case K_DOWNARROW:
|
case K_DOWNARROW:
|
||||||
case K_RIGHTARROW:
|
case K_RIGHTARROW:
|
||||||
S_LocalSound ("misc/menu1.wav");
|
S_LocalSound ("misc/menu1.wav");
|
||||||
keys_cursor++;
|
do
|
||||||
if (keys_cursor >= (int)NUMCOMMANDS)
|
{
|
||||||
keys_cursor = 0;
|
keys_cursor++;
|
||||||
|
if (keys_cursor >= numbindnames)
|
||||||
|
keys_cursor = keys_first = 0;
|
||||||
|
else if (keys_cursor == numbindnames-1)
|
||||||
|
break;
|
||||||
|
} while (!strcmp(bindnames[keys_cursor].cmd, "-"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case K_ENTER: // go into bind mode
|
case K_ENTER: // go into bind mode
|
||||||
case K_KP_ENTER:
|
case K_KP_ENTER:
|
||||||
case K_ABUTTON:
|
case K_ABUTTON:
|
||||||
M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
|
M_FindKeysForCommand (bindnames[keys_cursor].cmd, keys);
|
||||||
S_LocalSound ("misc/menu2.wav");
|
S_LocalSound ("misc/menu2.wav");
|
||||||
if (keys[2] != -1)
|
if (keys[2] != -1)
|
||||||
M_UnbindCommand (bindnames[keys_cursor][0]);
|
M_UnbindCommand (bindnames[keys_cursor].cmd);
|
||||||
bind_grab = true;
|
bind_grab = true;
|
||||||
IN_Activate(); // activate to allow mouse key binding
|
IN_Activate(); // activate to allow mouse key binding
|
||||||
break;
|
break;
|
||||||
|
@ -1527,7 +1628,7 @@ void M_Keys_Key (int k)
|
||||||
case K_BACKSPACE: // delete bindings
|
case K_BACKSPACE: // delete bindings
|
||||||
case K_DEL:
|
case K_DEL:
|
||||||
S_LocalSound ("misc/menu2.wav");
|
S_LocalSound ("misc/menu2.wav");
|
||||||
M_UnbindCommand (bindnames[keys_cursor][0]);
|
M_UnbindCommand (bindnames[keys_cursor].cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1696,7 +1797,7 @@ void M_Quit_Draw (void) //johnfitz -- modified for new quit message
|
||||||
m_state = m_quit;
|
m_state = m_quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(msg1, "QuakeSpasm " QUAKESPASM_VER_STRING);
|
sprintf(msg1, ENGINE_NAME_AND_VER);
|
||||||
|
|
||||||
//okay, this is kind of fucked up. M_DrawTextBox will always act as if
|
//okay, this is kind of fucked up. M_DrawTextBox will always act as if
|
||||||
//width is even. Also, the width and lines values are for the interior of the box,
|
//width is even. Also, the width and lines values are for the interior of the box,
|
||||||
|
@ -1715,8 +1816,8 @@ void M_Quit_Draw (void) //johnfitz -- modified for new quit message
|
||||||
/* LAN CONFIG MENU */
|
/* LAN CONFIG MENU */
|
||||||
|
|
||||||
int lanConfig_cursor = -1;
|
int lanConfig_cursor = -1;
|
||||||
int lanConfig_cursor_table [] = {72, 92, 124};
|
int lanConfig_cursor_table [] = {72, 92, 100, 132};
|
||||||
#define NUM_LANCONFIG_CMDS 3
|
#define NUM_LANCONFIG_CMDS 4
|
||||||
|
|
||||||
int lanConfig_port;
|
int lanConfig_port;
|
||||||
char lanConfig_portname[6];
|
char lanConfig_portname[6];
|
||||||
|
@ -1735,7 +1836,7 @@ void M_Menu_LanConfig_f (void)
|
||||||
else
|
else
|
||||||
lanConfig_cursor = 1;
|
lanConfig_cursor = 1;
|
||||||
}
|
}
|
||||||
if (StartingGame && lanConfig_cursor == 2)
|
if (StartingGame && lanConfig_cursor >= 2)
|
||||||
lanConfig_cursor = 1;
|
lanConfig_cursor = 1;
|
||||||
lanConfig_port = DEFAULTnet_hostport;
|
lanConfig_port = DEFAULTnet_hostport;
|
||||||
sprintf(lanConfig_portname, "%u", lanConfig_port);
|
sprintf(lanConfig_portname, "%u", lanConfig_port);
|
||||||
|
@ -1772,7 +1873,20 @@ void M_LanConfig_Draw (void)
|
||||||
if (IPXConfig)
|
if (IPXConfig)
|
||||||
M_Print (basex+9*8, 52, my_ipx_address);
|
M_Print (basex+9*8, 52, my_ipx_address);
|
||||||
else
|
else
|
||||||
M_Print (basex+9*8, 52, my_tcpip_address);
|
{
|
||||||
|
if (ipv4Available && ipv6Available)
|
||||||
|
{
|
||||||
|
M_Print (basex+9*8, 52-4, my_ipv4_address);
|
||||||
|
M_Print (basex+9*8, 52+4, my_ipv6_address);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ipv4Available)
|
||||||
|
M_Print (basex+9*8, 52, my_ipv4_address);
|
||||||
|
if (ipv6Available)
|
||||||
|
M_Print (basex+9*8, 52, my_ipv6_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
M_Print (basex, lanConfig_cursor_table[0], "Port");
|
M_Print (basex, lanConfig_cursor_table[0], "Port");
|
||||||
M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
|
M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
|
||||||
|
@ -1781,9 +1895,10 @@ void M_LanConfig_Draw (void)
|
||||||
if (JoiningGame)
|
if (JoiningGame)
|
||||||
{
|
{
|
||||||
M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
|
M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
|
||||||
|
M_Print (basex, lanConfig_cursor_table[2], "Search for public games...");
|
||||||
M_Print (basex, 108, "Join game at:");
|
M_Print (basex, 108, "Join game at:");
|
||||||
M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
|
M_DrawTextBox (basex+8, lanConfig_cursor_table[3]-8, 22, 1);
|
||||||
M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
|
M_Print (basex+16, lanConfig_cursor_table[3], lanConfig_joinname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1796,8 +1911,8 @@ void M_LanConfig_Draw (void)
|
||||||
if (lanConfig_cursor == 0)
|
if (lanConfig_cursor == 0)
|
||||||
M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
|
M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
|
||||||
|
|
||||||
if (lanConfig_cursor == 2)
|
if (lanConfig_cursor == 3)
|
||||||
M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
|
M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [3], 10+((int)(realtime*4)&1));
|
||||||
|
|
||||||
if (*m_return_reason)
|
if (*m_return_reason)
|
||||||
M_PrintWhite (basex, 148, m_return_reason);
|
M_PrintWhite (basex, 148, m_return_reason);
|
||||||
|
@ -1839,26 +1954,26 @@ void M_LanConfig_Key (int key)
|
||||||
|
|
||||||
M_ConfigureNetSubsystem ();
|
M_ConfigureNetSubsystem ();
|
||||||
|
|
||||||
if (lanConfig_cursor == 1)
|
if (StartingGame)
|
||||||
{
|
{
|
||||||
if (StartingGame)
|
if (lanConfig_cursor == 1)
|
||||||
{
|
|
||||||
M_Menu_GameOptions_f ();
|
M_Menu_GameOptions_f ();
|
||||||
break;
|
|
||||||
}
|
|
||||||
M_Menu_Search_f();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (lanConfig_cursor == 2)
|
|
||||||
{
|
{
|
||||||
m_return_state = m_state;
|
if (lanConfig_cursor == 1)
|
||||||
m_return_onerror = true;
|
M_Menu_Search_f(SLIST_LAN);
|
||||||
IN_Activate();
|
else if (lanConfig_cursor == 2)
|
||||||
key_dest = key_game;
|
M_Menu_Search_f(SLIST_INTERNET);
|
||||||
m_state = m_none;
|
else if (lanConfig_cursor == 3)
|
||||||
Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
|
{
|
||||||
break;
|
m_return_state = m_state;
|
||||||
|
m_return_onerror = true;
|
||||||
|
IN_Activate();
|
||||||
|
key_dest = key_game;
|
||||||
|
m_state = m_none;
|
||||||
|
Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1870,7 +1985,7 @@ void M_LanConfig_Key (int key)
|
||||||
lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
|
lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lanConfig_cursor == 2)
|
if (lanConfig_cursor == 3)
|
||||||
{
|
{
|
||||||
if (strlen(lanConfig_joinname))
|
if (strlen(lanConfig_joinname))
|
||||||
lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
|
lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
|
||||||
|
@ -1878,7 +1993,7 @@ void M_LanConfig_Key (int key)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StartingGame && lanConfig_cursor == 2)
|
if (StartingGame && lanConfig_cursor >= 2)
|
||||||
{
|
{
|
||||||
if (key == K_UPARROW)
|
if (key == K_UPARROW)
|
||||||
lanConfig_cursor = 1;
|
lanConfig_cursor = 1;
|
||||||
|
@ -1911,7 +2026,7 @@ void M_LanConfig_Char (int key)
|
||||||
lanConfig_portname[l] = key;
|
lanConfig_portname[l] = key;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 3:
|
||||||
l = strlen(lanConfig_joinname);
|
l = strlen(lanConfig_joinname);
|
||||||
if (l < 21)
|
if (l < 21)
|
||||||
{
|
{
|
||||||
|
@ -1925,7 +2040,7 @@ void M_LanConfig_Char (int key)
|
||||||
|
|
||||||
qboolean M_LanConfig_TextEntry (void)
|
qboolean M_LanConfig_TextEntry (void)
|
||||||
{
|
{
|
||||||
return (lanConfig_cursor == 0 || lanConfig_cursor == 2);
|
return (lanConfig_cursor == 0 || lanConfig_cursor == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -2075,6 +2190,8 @@ episode_t rogueepisodes[] =
|
||||||
{"Deathmatch Arena", 16, 1}
|
{"Deathmatch Arena", 16, 1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern cvar_t sv_public;
|
||||||
|
|
||||||
int startepisode;
|
int startepisode;
|
||||||
int startlevel;
|
int startlevel;
|
||||||
int maxplayers;
|
int maxplayers;
|
||||||
|
@ -2094,32 +2211,43 @@ void M_Menu_GameOptions_f (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
|
int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 104, 120, 128};
|
||||||
#define NUM_GAMEOPTIONS 9
|
#define NUM_GAMEOPTIONS 10
|
||||||
int gameoptions_cursor;
|
int gameoptions_cursor;
|
||||||
|
|
||||||
void M_GameOptions_Draw (void)
|
void M_GameOptions_Draw (void)
|
||||||
{
|
{
|
||||||
qpic_t *p;
|
qpic_t *p;
|
||||||
int x;
|
int x;
|
||||||
|
int y = 40;
|
||||||
|
|
||||||
M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
|
M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
|
||||||
p = Draw_CachePic ("gfx/p_multi.lmp");
|
p = Draw_CachePic ("gfx/p_multi.lmp");
|
||||||
M_DrawPic ( (320-p->width)/2, 4, p);
|
M_DrawPic ( (320-p->width)/2, 4, p);
|
||||||
|
|
||||||
M_DrawTextBox (152, 32, 10, 1);
|
M_DrawTextBox (152, y-8, 10, 1);
|
||||||
M_Print (160, 40, "begin game");
|
M_Print (160, y, "begin game");
|
||||||
|
y+=16;
|
||||||
|
|
||||||
M_Print (0, 56, " Max players");
|
M_Print (0, y, " Max players");
|
||||||
M_Print (160, 56, va("%i", maxplayers) );
|
M_Print (160, y, va("%i", maxplayers) );
|
||||||
|
y+=8;
|
||||||
|
|
||||||
M_Print (0, 64, " Game Type");
|
M_Print (0, y, " Public");
|
||||||
if (coop.value)
|
if (sv_public.value)
|
||||||
M_Print (160, 64, "Cooperative");
|
M_Print (160, y, "Yes");
|
||||||
else
|
else
|
||||||
M_Print (160, 64, "Deathmatch");
|
M_Print (160, y, "No");
|
||||||
|
y+=8;
|
||||||
|
|
||||||
M_Print (0, 72, " Teamplay");
|
M_Print (0, y, " Game Type");
|
||||||
|
if (coop.value)
|
||||||
|
M_Print (160, y, "Cooperative");
|
||||||
|
else
|
||||||
|
M_Print (160, y, "Deathmatch");
|
||||||
|
y+=8;
|
||||||
|
|
||||||
|
M_Print (0, y, " Teamplay");
|
||||||
if (rogue)
|
if (rogue)
|
||||||
{
|
{
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
@ -2134,7 +2262,7 @@ void M_GameOptions_Draw (void)
|
||||||
case 6: msg = "Three Team CTF"; break;
|
case 6: msg = "Three Team CTF"; break;
|
||||||
default: msg = "Off"; break;
|
default: msg = "Off"; break;
|
||||||
}
|
}
|
||||||
M_Print (160, 72, msg);
|
M_Print (160, y, msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2146,59 +2274,67 @@ void M_GameOptions_Draw (void)
|
||||||
case 2: msg = "Friendly Fire"; break;
|
case 2: msg = "Friendly Fire"; break;
|
||||||
default: msg = "Off"; break;
|
default: msg = "Off"; break;
|
||||||
}
|
}
|
||||||
M_Print (160, 72, msg);
|
M_Print (160, y, msg);
|
||||||
}
|
}
|
||||||
|
y+=8;
|
||||||
|
|
||||||
M_Print (0, 80, " Skill");
|
M_Print (0, y, " Skill");
|
||||||
if (skill.value == 0)
|
if (skill.value == 0)
|
||||||
M_Print (160, 80, "Easy difficulty");
|
M_Print (160, y, "Easy difficulty");
|
||||||
else if (skill.value == 1)
|
else if (skill.value == 1)
|
||||||
M_Print (160, 80, "Normal difficulty");
|
M_Print (160, y, "Normal difficulty");
|
||||||
else if (skill.value == 2)
|
else if (skill.value == 2)
|
||||||
M_Print (160, 80, "Hard difficulty");
|
M_Print (160, y, "Hard difficulty");
|
||||||
else
|
else
|
||||||
M_Print (160, 80, "Nightmare difficulty");
|
M_Print (160, y, "Nightmare difficulty");
|
||||||
|
y+=8;
|
||||||
|
|
||||||
M_Print (0, 88, " Frag Limit");
|
M_Print (0, y, " Frag Limit");
|
||||||
if (fraglimit.value == 0)
|
if (fraglimit.value == 0)
|
||||||
M_Print (160, 88, "none");
|
M_Print (160, y, "none");
|
||||||
else
|
else
|
||||||
M_Print (160, 88, va("%i frags", (int)fraglimit.value));
|
M_Print (160, y, va("%i frags", (int)fraglimit.value));
|
||||||
|
y+=8;
|
||||||
|
|
||||||
M_Print (0, 96, " Time Limit");
|
M_Print (0, y, " Time Limit");
|
||||||
if (timelimit.value == 0)
|
if (timelimit.value == 0)
|
||||||
M_Print (160, 96, "none");
|
M_Print (160, y, "none");
|
||||||
else
|
else
|
||||||
M_Print (160, 96, va("%i minutes", (int)timelimit.value));
|
M_Print (160, y, va("%i minutes", (int)timelimit.value));
|
||||||
|
y+=8;
|
||||||
|
|
||||||
M_Print (0, 112, " Episode");
|
y+=8;
|
||||||
|
|
||||||
|
M_Print (0, y, " Episode");
|
||||||
// MED 01/06/97 added hipnotic episodes
|
// MED 01/06/97 added hipnotic episodes
|
||||||
if (hipnotic)
|
if (hipnotic)
|
||||||
M_Print (160, 112, hipnoticepisodes[startepisode].description);
|
M_Print (160, y, hipnoticepisodes[startepisode].description);
|
||||||
// PGM 01/07/97 added rogue episodes
|
// PGM 01/07/97 added rogue episodes
|
||||||
else if (rogue)
|
else if (rogue)
|
||||||
M_Print (160, 112, rogueepisodes[startepisode].description);
|
M_Print (160, y, rogueepisodes[startepisode].description);
|
||||||
else
|
else
|
||||||
M_Print (160, 112, episodes[startepisode].description);
|
M_Print (160, y, episodes[startepisode].description);
|
||||||
|
y+=8;
|
||||||
|
|
||||||
M_Print (0, 120, " Level");
|
M_Print (0, y, " Level");
|
||||||
// MED 01/06/97 added hipnotic episodes
|
// MED 01/06/97 added hipnotic episodes
|
||||||
if (hipnotic)
|
if (hipnotic)
|
||||||
{
|
{
|
||||||
M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
|
M_Print (160, y, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
|
||||||
M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
|
M_Print (160, y+8, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
|
||||||
}
|
}
|
||||||
// PGM 01/07/97 added rogue episodes
|
// PGM 01/07/97 added rogue episodes
|
||||||
else if (rogue)
|
else if (rogue)
|
||||||
{
|
{
|
||||||
M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
|
M_Print (160, y, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
|
||||||
M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
|
M_Print (160, y+8, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);
|
M_Print (160, y, levels[episodes[startepisode].firstLevel + startlevel].description);
|
||||||
M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);
|
M_Print (160, y+8, levels[episodes[startepisode].firstLevel + startlevel].name);
|
||||||
}
|
}
|
||||||
|
y+=8;
|
||||||
|
|
||||||
// line cursor
|
// line cursor
|
||||||
M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
|
M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
|
||||||
|
@ -2243,10 +2379,14 @@ void M_NetStart_Change (int dir)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
Cvar_Set ("coop", coop.value ? "0" : "1");
|
Cvar_SetQuick (&sv_public, sv_public.value ? "0" : "1");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
|
Cvar_Set ("coop", coop.value ? "0" : "1");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
count = (rogue) ? 6 : 2;
|
count = (rogue) ? 6 : 2;
|
||||||
f = teamplay.value + dir;
|
f = teamplay.value + dir;
|
||||||
if (f > count) f = 0;
|
if (f > count) f = 0;
|
||||||
|
@ -2254,28 +2394,28 @@ void M_NetStart_Change (int dir)
|
||||||
Cvar_SetValue ("teamplay", f);
|
Cvar_SetValue ("teamplay", f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 5:
|
||||||
f = skill.value + dir;
|
f = skill.value + dir;
|
||||||
if (f > 3) f = 0;
|
if (f > 3) f = 0;
|
||||||
else if (f < 0) f = 3;
|
else if (f < 0) f = 3;
|
||||||
Cvar_SetValue ("skill", f);
|
Cvar_SetValue ("skill", f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 6:
|
||||||
f = fraglimit.value + dir * 10;
|
f = fraglimit.value + dir * 10;
|
||||||
if (f > 100) f = 0;
|
if (f > 100) f = 0;
|
||||||
else if (f < 0) f = 100;
|
else if (f < 0) f = 100;
|
||||||
Cvar_SetValue ("fraglimit", f);
|
Cvar_SetValue ("fraglimit", f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 7:
|
||||||
f = timelimit.value + dir * 5;
|
f = timelimit.value + dir * 5;
|
||||||
if (f > 60) f = 0;
|
if (f > 60) f = 0;
|
||||||
else if (f < 0) f = 60;
|
else if (f < 0) f = 60;
|
||||||
Cvar_SetValue ("timelimit", f);
|
Cvar_SetValue ("timelimit", f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7:
|
case 8:
|
||||||
startepisode += dir;
|
startepisode += dir;
|
||||||
//MED 01/06/97 added hipnotic count
|
//MED 01/06/97 added hipnotic count
|
||||||
if (hipnotic)
|
if (hipnotic)
|
||||||
|
@ -2298,7 +2438,7 @@ void M_NetStart_Change (int dir)
|
||||||
startlevel = 0;
|
startlevel = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 9:
|
||||||
startlevel += dir;
|
startlevel += dir;
|
||||||
//MED 01/06/97 added hipnotic episodes
|
//MED 01/06/97 added hipnotic episodes
|
||||||
if (hipnotic)
|
if (hipnotic)
|
||||||
|
@ -2387,15 +2527,16 @@ void M_GameOptions_Key (int key)
|
||||||
|
|
||||||
qboolean searchComplete = false;
|
qboolean searchComplete = false;
|
||||||
double searchCompleteTime;
|
double searchCompleteTime;
|
||||||
|
enum slistScope_e searchLastScope = SLIST_LAN;
|
||||||
|
|
||||||
void M_Menu_Search_f (void)
|
void M_Menu_Search_f (enum slistScope_e scope)
|
||||||
{
|
{
|
||||||
IN_Deactivate(modestate == MS_WINDOWED);
|
IN_Deactivate(modestate == MS_WINDOWED);
|
||||||
key_dest = key_menu;
|
key_dest = key_menu;
|
||||||
m_state = m_search;
|
m_state = m_search;
|
||||||
m_entersound = false;
|
m_entersound = false;
|
||||||
slistSilent = true;
|
slistSilent = true;
|
||||||
slistLocal = false;
|
slistScope = searchLastScope = scope;
|
||||||
searchComplete = false;
|
searchComplete = false;
|
||||||
NET_Slist_f();
|
NET_Slist_f();
|
||||||
|
|
||||||
|
@ -2446,7 +2587,8 @@ void M_Search_Key (int key)
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
/* SLIST MENU */
|
/* SLIST MENU */
|
||||||
|
|
||||||
int slist_cursor;
|
size_t slist_cursor;
|
||||||
|
size_t slist_first;
|
||||||
qboolean slist_sorted;
|
qboolean slist_sorted;
|
||||||
|
|
||||||
void M_Menu_ServerList_f (void)
|
void M_Menu_ServerList_f (void)
|
||||||
|
@ -2456,6 +2598,7 @@ void M_Menu_ServerList_f (void)
|
||||||
m_state = m_slist;
|
m_state = m_slist;
|
||||||
m_entersound = true;
|
m_entersound = true;
|
||||||
slist_cursor = 0;
|
slist_cursor = 0;
|
||||||
|
slist_first = 0;
|
||||||
m_return_onerror = false;
|
m_return_onerror = false;
|
||||||
m_return_reason[0] = 0;
|
m_return_reason[0] = 0;
|
||||||
slist_sorted = false;
|
slist_sorted = false;
|
||||||
|
@ -2464,7 +2607,7 @@ void M_Menu_ServerList_f (void)
|
||||||
|
|
||||||
void M_ServerList_Draw (void)
|
void M_ServerList_Draw (void)
|
||||||
{
|
{
|
||||||
int n;
|
size_t n, slist_shown;
|
||||||
qpic_t *p;
|
qpic_t *p;
|
||||||
|
|
||||||
if (!slist_sorted)
|
if (!slist_sorted)
|
||||||
|
@ -2473,11 +2616,19 @@ void M_ServerList_Draw (void)
|
||||||
NET_SlistSort ();
|
NET_SlistSort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slist_shown = hostCacheCount;
|
||||||
|
if (slist_shown > (200-32)/8)
|
||||||
|
slist_shown = (200-32)/8;
|
||||||
|
if (slist_first+slist_shown-1 < slist_cursor)
|
||||||
|
slist_first = slist_cursor-(slist_shown-1);
|
||||||
|
if (slist_first > slist_cursor)
|
||||||
|
slist_first = slist_cursor;
|
||||||
|
|
||||||
p = Draw_CachePic ("gfx/p_multi.lmp");
|
p = Draw_CachePic ("gfx/p_multi.lmp");
|
||||||
M_DrawPic ( (320-p->width)/2, 4, p);
|
M_DrawPic ( (320-p->width)/2, 4, p);
|
||||||
for (n = 0; n < hostCacheCount; n++)
|
for (n = 0; n < slist_shown; n++)
|
||||||
M_Print (16, 32 + 8*n, NET_SlistPrintServer (n));
|
M_Print (16, 32 + 8*n, NET_SlistPrintServer (slist_first+n));
|
||||||
M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
|
M_DrawCharacter (0, 32 + (slist_cursor-slist_first)*8, 12+((int)(realtime*4)&1));
|
||||||
|
|
||||||
if (*m_return_reason)
|
if (*m_return_reason)
|
||||||
M_PrintWhite (16, 148, m_return_reason);
|
M_PrintWhite (16, 148, m_return_reason);
|
||||||
|
@ -2494,14 +2645,14 @@ void M_ServerList_Key (int k)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case K_SPACE:
|
case K_SPACE:
|
||||||
M_Menu_Search_f ();
|
M_Menu_Search_f (searchLastScope);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case K_UPARROW:
|
case K_UPARROW:
|
||||||
case K_LEFTARROW:
|
case K_LEFTARROW:
|
||||||
S_LocalSound ("misc/menu1.wav");
|
S_LocalSound ("misc/menu1.wav");
|
||||||
slist_cursor--;
|
slist_cursor--;
|
||||||
if (slist_cursor < 0)
|
if (slist_cursor >= hostCacheCount)
|
||||||
slist_cursor = hostCacheCount - 1;
|
slist_cursor = hostCacheCount - 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
29
Quake/net.h
29
Quake/net.h
|
@ -56,12 +56,20 @@ struct qsocket_s *NET_Connect (const char *host);
|
||||||
// called by client to connect to a host. Returns -1 if not able to
|
// called by client to connect to a host. Returns -1 if not able to
|
||||||
|
|
||||||
double NET_QSocketGetTime (const struct qsocket_s *sock);
|
double NET_QSocketGetTime (const struct qsocket_s *sock);
|
||||||
const char *NET_QSocketGetAddressString (const struct qsocket_s *sock);
|
const char *NET_QSocketGetTrueAddressString (const struct qsocket_s *sock);
|
||||||
|
const char *NET_QSocketGetMaskedAddressString (const struct qsocket_s *sock);
|
||||||
|
qboolean NET_QSocketGetProQuakeAngleHack (const struct qsocket_s *sock);
|
||||||
|
int NET_QSocketGetSequenceIn (const struct qsocket_s *sock);
|
||||||
|
int NET_QSocketGetSequenceOut (const struct qsocket_s *sock);
|
||||||
|
void NET_QSocketSetMSS(struct qsocket_s *s, int mss);
|
||||||
|
|
||||||
qboolean NET_CanSendMessage (struct qsocket_s *sock);
|
qboolean NET_CanSendMessage (struct qsocket_s *sock);
|
||||||
// Returns true or false if the given qsocket can currently accept a
|
// Returns true or false if the given qsocket can currently accept a
|
||||||
// message to be transmitted.
|
// message to be transmitted.
|
||||||
|
|
||||||
|
struct qsocket_s *NET_GetServerMessage(void);
|
||||||
|
//returns data in net_message, qsocket says which client its from
|
||||||
|
|
||||||
int NET_GetMessage (struct qsocket_s *sock);
|
int NET_GetMessage (struct qsocket_s *sock);
|
||||||
// returns data in net_message sizebuf
|
// returns data in net_message sizebuf
|
||||||
// returns 0 if no data is waiting
|
// returns 0 if no data is waiting
|
||||||
|
@ -94,22 +102,29 @@ void NET_Poll (void);
|
||||||
// Server list related globals:
|
// Server list related globals:
|
||||||
extern qboolean slistInProgress;
|
extern qboolean slistInProgress;
|
||||||
extern qboolean slistSilent;
|
extern qboolean slistSilent;
|
||||||
extern qboolean slistLocal;
|
extern enum slistScope_e
|
||||||
|
{
|
||||||
|
SLIST_LOOP,
|
||||||
|
SLIST_LAN,
|
||||||
|
SLIST_INTERNET
|
||||||
|
} slistScope;
|
||||||
|
|
||||||
extern int hostCacheCount;
|
extern size_t hostCacheCount;
|
||||||
|
|
||||||
void NET_Slist_f (void);
|
void NET_Slist_f (void);
|
||||||
void NET_SlistSort (void);
|
void NET_SlistSort (void);
|
||||||
const char *NET_SlistPrintServer (int n);
|
const char *NET_SlistPrintServer (size_t n);
|
||||||
const char *NET_SlistPrintServerName (int n);
|
const char *NET_SlistPrintServerName (size_t n);
|
||||||
|
|
||||||
|
|
||||||
/* FIXME: driver related, but public:
|
/* FIXME: driver related, but public:
|
||||||
*/
|
*/
|
||||||
extern qboolean ipxAvailable;
|
extern qboolean ipxAvailable;
|
||||||
extern qboolean tcpipAvailable;
|
extern qboolean ipv4Available;
|
||||||
|
extern qboolean ipv6Available;
|
||||||
extern char my_ipx_address[NET_NAMELEN];
|
extern char my_ipx_address[NET_NAMELEN];
|
||||||
extern char my_tcpip_address[NET_NAMELEN];
|
extern char my_ipv4_address[NET_NAMELEN];
|
||||||
|
extern char my_ipv6_address[NET_NAMELEN];
|
||||||
|
|
||||||
#endif /* _QUAKE_NET_H */
|
#endif /* _QUAKE_NET_H */
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ net_driver_t net_drivers[] =
|
||||||
Loop_SearchForHosts,
|
Loop_SearchForHosts,
|
||||||
Loop_Connect,
|
Loop_Connect,
|
||||||
Loop_CheckNewConnections,
|
Loop_CheckNewConnections,
|
||||||
|
Loop_GetAnyMessage,
|
||||||
Loop_GetMessage,
|
Loop_GetMessage,
|
||||||
Loop_SendMessage,
|
Loop_SendMessage,
|
||||||
Loop_SendUnreliableMessage,
|
Loop_SendUnreliableMessage,
|
||||||
|
@ -53,6 +54,7 @@ net_driver_t net_drivers[] =
|
||||||
Datagram_SearchForHosts,
|
Datagram_SearchForHosts,
|
||||||
Datagram_Connect,
|
Datagram_Connect,
|
||||||
Datagram_CheckNewConnections,
|
Datagram_CheckNewConnections,
|
||||||
|
Datagram_GetAnyMessage,
|
||||||
Datagram_GetMessage,
|
Datagram_GetMessage,
|
||||||
Datagram_SendMessage,
|
Datagram_SendMessage,
|
||||||
Datagram_SendUnreliableMessage,
|
Datagram_SendUnreliableMessage,
|
||||||
|
@ -72,21 +74,43 @@ net_landriver_t net_landrivers[] =
|
||||||
{ "UDP",
|
{ "UDP",
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
UDP_Init,
|
UDP4_Init,
|
||||||
UDP_Shutdown,
|
UDP4_Shutdown,
|
||||||
UDP_Listen,
|
UDP4_Listen,
|
||||||
UDP_OpenSocket,
|
UDP4_OpenSocket,
|
||||||
UDP_CloseSocket,
|
UDP_CloseSocket,
|
||||||
UDP_Connect,
|
UDP_Connect,
|
||||||
UDP_CheckNewConnections,
|
UDP4_CheckNewConnections,
|
||||||
UDP_Read,
|
UDP_Read,
|
||||||
UDP_Write,
|
UDP_Write,
|
||||||
UDP_Broadcast,
|
UDP4_Broadcast,
|
||||||
UDP_AddrToString,
|
UDP_AddrToString,
|
||||||
UDP_StringToAddr,
|
UDP4_StringToAddr,
|
||||||
UDP_GetSocketAddr,
|
UDP_GetSocketAddr,
|
||||||
UDP_GetNameFromAddr,
|
UDP_GetNameFromAddr,
|
||||||
UDP_GetAddrFromName,
|
UDP4_GetAddrFromName,
|
||||||
|
UDP_AddrCompare,
|
||||||
|
UDP_GetSocketPort,
|
||||||
|
UDP_SetSocketPort
|
||||||
|
},
|
||||||
|
{ "UDP6",
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
UDP6_Init,
|
||||||
|
UDP6_Shutdown,
|
||||||
|
UDP6_Listen,
|
||||||
|
UDP6_OpenSocket,
|
||||||
|
UDP_CloseSocket,
|
||||||
|
UDP_Connect,
|
||||||
|
UDP6_CheckNewConnections,
|
||||||
|
UDP_Read,
|
||||||
|
UDP_Write,
|
||||||
|
UDP6_Broadcast,
|
||||||
|
UDP_AddrToString,
|
||||||
|
UDP6_StringToAddr,
|
||||||
|
UDP_GetSocketAddr,
|
||||||
|
UDP_GetNameFromAddr,
|
||||||
|
UDP6_GetAddrFromName,
|
||||||
UDP_AddrCompare,
|
UDP_AddrCompare,
|
||||||
UDP_GetSocketPort,
|
UDP_GetSocketPort,
|
||||||
UDP_SetSocketPort
|
UDP_SetSocketPort
|
||||||
|
|
|
@ -32,7 +32,7 @@ struct qsockaddr
|
||||||
#else
|
#else
|
||||||
short qsa_family;
|
short qsa_family;
|
||||||
#endif /* BSD, sockaddr */
|
#endif /* BSD, sockaddr */
|
||||||
unsigned char qsa_data[14];
|
unsigned char qsa_data[62];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NET_HEADERSIZE (2 * sizeof(unsigned int))
|
#define NET_HEADERSIZE (2 * sizeof(unsigned int))
|
||||||
|
@ -120,12 +120,14 @@ CCREP_RULE_INFO
|
||||||
#define CCREQ_SERVER_INFO 0x02
|
#define CCREQ_SERVER_INFO 0x02
|
||||||
#define CCREQ_PLAYER_INFO 0x03
|
#define CCREQ_PLAYER_INFO 0x03
|
||||||
#define CCREQ_RULE_INFO 0x04
|
#define CCREQ_RULE_INFO 0x04
|
||||||
|
#define CCREQ_RCON 0x05
|
||||||
|
|
||||||
#define CCREP_ACCEPT 0x81
|
#define CCREP_ACCEPT 0x81
|
||||||
#define CCREP_REJECT 0x82
|
#define CCREP_REJECT 0x82
|
||||||
#define CCREP_SERVER_INFO 0x83
|
#define CCREP_SERVER_INFO 0x83
|
||||||
#define CCREP_PLAYER_INFO 0x84
|
#define CCREP_PLAYER_INFO 0x84
|
||||||
#define CCREP_RULE_INFO 0x85
|
#define CCREP_RULE_INFO 0x85
|
||||||
|
#define CCREP_RCON 0x86
|
||||||
|
|
||||||
typedef struct qsocket_s
|
typedef struct qsocket_s
|
||||||
{
|
{
|
||||||
|
@ -134,6 +136,7 @@ typedef struct qsocket_s
|
||||||
double lastMessageTime;
|
double lastMessageTime;
|
||||||
double lastSendTime;
|
double lastSendTime;
|
||||||
|
|
||||||
|
qboolean isvirtual; //qsocket is emulated by the network layer (closing will not close any system sockets).
|
||||||
qboolean disconnected;
|
qboolean disconnected;
|
||||||
qboolean canSend;
|
qboolean canSend;
|
||||||
qboolean sendNext;
|
qboolean sendNext;
|
||||||
|
@ -155,8 +158,12 @@ typedef struct qsocket_s
|
||||||
byte receiveMessage [NET_MAXMESSAGE];
|
byte receiveMessage [NET_MAXMESSAGE];
|
||||||
|
|
||||||
struct qsockaddr addr;
|
struct qsockaddr addr;
|
||||||
char address[NET_NAMELEN];
|
char trueaddress[NET_NAMELEN]; //lazy address string
|
||||||
|
char maskedaddress[NET_NAMELEN]; //addresses for this player that may be displayed publically
|
||||||
|
|
||||||
|
qboolean proquake_angle_hack; //1 if we're trying, 2 if the server acked.
|
||||||
|
int max_datagram; //32000 for local, 1442 for 666, 1024 for 15. this is for reliable fragments.
|
||||||
|
int pending_max_datagram; //don't change the mtu if we're resending, as that would confuse the peer.
|
||||||
} qsocket_t;
|
} qsocket_t;
|
||||||
|
|
||||||
extern qsocket_t *net_activeSockets;
|
extern qsocket_t *net_activeSockets;
|
||||||
|
@ -170,7 +177,7 @@ typedef struct
|
||||||
sys_socket_t controlSock;
|
sys_socket_t controlSock;
|
||||||
sys_socket_t (*Init) (void);
|
sys_socket_t (*Init) (void);
|
||||||
void (*Shutdown) (void);
|
void (*Shutdown) (void);
|
||||||
void (*Listen) (qboolean state);
|
sys_socket_t (*Listen) (qboolean state);
|
||||||
sys_socket_t (*Open_Socket) (int port);
|
sys_socket_t (*Open_Socket) (int port);
|
||||||
int (*Close_Socket) (sys_socket_t socketid);
|
int (*Close_Socket) (sys_socket_t socketid);
|
||||||
int (*Connect) (sys_socket_t socketid, struct qsockaddr *addr);
|
int (*Connect) (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
|
@ -178,7 +185,7 @@ typedef struct
|
||||||
int (*Read) (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
int (*Read) (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
int (*Write) (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
int (*Write) (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
int (*Broadcast) (sys_socket_t socketid, byte *buf, int len);
|
int (*Broadcast) (sys_socket_t socketid, byte *buf, int len);
|
||||||
const char * (*AddrToString) (struct qsockaddr *addr);
|
const char * (*AddrToString) (struct qsockaddr *addr, qboolean masked);
|
||||||
int (*StringToAddr) (const char *string, struct qsockaddr *addr);
|
int (*StringToAddr) (const char *string, struct qsockaddr *addr);
|
||||||
int (*GetSocketAddr) (sys_socket_t socketid, struct qsockaddr *addr);
|
int (*GetSocketAddr) (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
int (*GetNameFromAddr) (struct qsockaddr *addr, char *name);
|
int (*GetNameFromAddr) (struct qsockaddr *addr, char *name);
|
||||||
|
@ -186,6 +193,8 @@ typedef struct
|
||||||
int (*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
int (*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||||
int (*GetSocketPort) (struct qsockaddr *addr);
|
int (*GetSocketPort) (struct qsockaddr *addr);
|
||||||
int (*SetSocketPort) (struct qsockaddr *addr, int port);
|
int (*SetSocketPort) (struct qsockaddr *addr, int port);
|
||||||
|
|
||||||
|
sys_socket_t listeningSock;
|
||||||
} net_landriver_t;
|
} net_landriver_t;
|
||||||
|
|
||||||
#define MAX_NET_DRIVERS 8
|
#define MAX_NET_DRIVERS 8
|
||||||
|
@ -198,9 +207,10 @@ typedef struct
|
||||||
qboolean initialized;
|
qboolean initialized;
|
||||||
int (*Init) (void);
|
int (*Init) (void);
|
||||||
void (*Listen) (qboolean state);
|
void (*Listen) (qboolean state);
|
||||||
void (*SearchForHosts) (qboolean xmit);
|
qboolean (*SearchForHosts) (qboolean xmit);
|
||||||
qsocket_t *(*Connect) (const char *host);
|
qsocket_t *(*Connect) (const char *host);
|
||||||
qsocket_t *(*CheckNewConnections) (void);
|
qsocket_t *(*CheckNewConnections) (void);
|
||||||
|
qsocket_t *(*QGetAnyMessage) (void);
|
||||||
int (*QGetMessage) (qsocket_t *sock);
|
int (*QGetMessage) (qsocket_t *sock);
|
||||||
int (*QSendMessage) (qsocket_t *sock, sizebuf_t *data);
|
int (*QSendMessage) (qsocket_t *sock, sizebuf_t *data);
|
||||||
int (*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data);
|
int (*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data);
|
||||||
|
@ -228,13 +238,13 @@ void NET_FreeQSocket(qsocket_t *);
|
||||||
double SetNetTime(void);
|
double SetNetTime(void);
|
||||||
|
|
||||||
|
|
||||||
#define HOSTCACHESIZE 8
|
#define HOSTCACHESIZE 128 //fixme: make dynamic.
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char name[16];
|
char name[16];
|
||||||
char map[16];
|
char map[16];
|
||||||
char cname[32];
|
char cname[NET_NAMELEN];
|
||||||
int users;
|
int users;
|
||||||
int maxusers;
|
int maxusers;
|
||||||
int driver;
|
int driver;
|
||||||
|
@ -242,7 +252,7 @@ typedef struct
|
||||||
struct qsockaddr addr;
|
struct qsockaddr addr;
|
||||||
} hostcache_t;
|
} hostcache_t;
|
||||||
|
|
||||||
extern int hostCacheCount;
|
extern size_t hostCacheCount;
|
||||||
extern hostcache_t hostcache[HOSTCACHESIZE];
|
extern hostcache_t hostcache[HOSTCACHESIZE];
|
||||||
|
|
||||||
|
|
||||||
|
|
1117
Quake/net_dgrm.c
1117
Quake/net_dgrm.c
File diff suppressed because it is too large
Load Diff
|
@ -24,9 +24,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
int Datagram_Init (void);
|
int Datagram_Init (void);
|
||||||
void Datagram_Listen (qboolean state);
|
void Datagram_Listen (qboolean state);
|
||||||
void Datagram_SearchForHosts (qboolean xmit);
|
qboolean Datagram_SearchForHosts (qboolean xmit);
|
||||||
qsocket_t *Datagram_Connect (const char *host);
|
qsocket_t *Datagram_Connect (const char *host);
|
||||||
qsocket_t *Datagram_CheckNewConnections (void);
|
qsocket_t *Datagram_CheckNewConnections (void);
|
||||||
|
qsocket_t *Datagram_GetAnyMessage (void);
|
||||||
int Datagram_GetMessage (qsocket_t *sock);
|
int Datagram_GetMessage (qsocket_t *sock);
|
||||||
int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data);
|
int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data);
|
||||||
int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
|
int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
|
||||||
|
|
|
@ -48,10 +48,10 @@ void Loop_Listen (qboolean state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Loop_SearchForHosts (qboolean xmit)
|
qboolean Loop_SearchForHosts (qboolean xmit)
|
||||||
{
|
{
|
||||||
if (!sv.active)
|
if (!sv.active)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
hostCacheCount = 1;
|
hostCacheCount = 1;
|
||||||
if (Q_strcmp(hostname.string, "UNNAMED") == 0)
|
if (Q_strcmp(hostname.string, "UNNAMED") == 0)
|
||||||
|
@ -63,6 +63,7 @@ void Loop_SearchForHosts (qboolean xmit)
|
||||||
hostcache[0].maxusers = svs.maxclients;
|
hostcache[0].maxusers = svs.maxclients;
|
||||||
hostcache[0].driver = net_driverlevel;
|
hostcache[0].driver = net_driverlevel;
|
||||||
Q_strcpy(hostcache[0].cname, "local");
|
Q_strcpy(hostcache[0].cname, "local");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,7 +81,8 @@ qsocket_t *Loop_Connect (const char *host)
|
||||||
Con_Printf("Loop_Connect: no qsocket available\n");
|
Con_Printf("Loop_Connect: no qsocket available\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Q_strcpy (loop_client->address, "localhost");
|
Q_strcpy (loop_client->trueaddress, "localhost");
|
||||||
|
Q_strcpy (loop_client->maskedaddress, "localhost");
|
||||||
}
|
}
|
||||||
loop_client->receiveMessageLength = 0;
|
loop_client->receiveMessageLength = 0;
|
||||||
loop_client->sendMessageLength = 0;
|
loop_client->sendMessageLength = 0;
|
||||||
|
@ -93,7 +95,8 @@ qsocket_t *Loop_Connect (const char *host)
|
||||||
Con_Printf("Loop_Connect: no qsocket available\n");
|
Con_Printf("Loop_Connect: no qsocket available\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Q_strcpy (loop_server->address, "LOCAL");
|
Q_strcpy (loop_server->trueaddress, "LOCAL");
|
||||||
|
Q_strcpy (loop_server->maskedaddress, "LOCAL");
|
||||||
}
|
}
|
||||||
loop_server->receiveMessageLength = 0;
|
loop_server->receiveMessageLength = 0;
|
||||||
loop_server->sendMessageLength = 0;
|
loop_server->sendMessageLength = 0;
|
||||||
|
@ -102,6 +105,8 @@ qsocket_t *Loop_Connect (const char *host)
|
||||||
loop_client->driverdata = (void *)loop_server;
|
loop_client->driverdata = (void *)loop_server;
|
||||||
loop_server->driverdata = (void *)loop_client;
|
loop_server->driverdata = (void *)loop_client;
|
||||||
|
|
||||||
|
loop_client->proquake_angle_hack = loop_server->proquake_angle_hack = true;
|
||||||
|
|
||||||
return loop_client;
|
return loop_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +132,6 @@ static int IntAlign(int value)
|
||||||
return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));
|
return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Loop_GetMessage (qsocket_t *sock)
|
int Loop_GetMessage (qsocket_t *sock)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -140,9 +144,19 @@ int Loop_GetMessage (qsocket_t *sock)
|
||||||
length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);
|
length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);
|
||||||
// alignment byte skipped here
|
// alignment byte skipped here
|
||||||
SZ_Clear (&net_message);
|
SZ_Clear (&net_message);
|
||||||
SZ_Write (&net_message, &sock->receiveMessage[4], length);
|
if (ret == 2)
|
||||||
|
{ //unreliables have sequences that we (now) care about so that clients can ack them.
|
||||||
|
sock->unreliableReceiveSequence = sock->receiveMessage[4] | (sock->receiveMessage[5]<<8) | (sock->receiveMessage[6]<<16) | (sock->receiveMessage[7]<<16);
|
||||||
|
sock->unreliableReceiveSequence++;
|
||||||
|
SZ_Write (&net_message, &sock->receiveMessage[8], length);
|
||||||
|
length = IntAlign(length + 8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //reliable
|
||||||
|
SZ_Write (&net_message, &sock->receiveMessage[4], length);
|
||||||
|
length = IntAlign(length + 4);
|
||||||
|
}
|
||||||
|
|
||||||
length = IntAlign(length + 4);
|
|
||||||
sock->receiveMessageLength -= length;
|
sock->receiveMessageLength -= length;
|
||||||
|
|
||||||
if (sock->receiveMessageLength)
|
if (sock->receiveMessageLength)
|
||||||
|
@ -154,6 +168,16 @@ int Loop_GetMessage (qsocket_t *sock)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qsocket_t *Loop_GetAnyMessage(void)
|
||||||
|
{
|
||||||
|
if (loop_server)
|
||||||
|
{
|
||||||
|
if (Loop_GetMessage(loop_server) > 0)
|
||||||
|
return loop_server;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data)
|
int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data)
|
||||||
{
|
{
|
||||||
|
@ -193,6 +217,7 @@ int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
|
||||||
{
|
{
|
||||||
byte *buffer;
|
byte *buffer;
|
||||||
int *bufferLength;
|
int *bufferLength;
|
||||||
|
int sequence = sock->unreliableSendSequence++;
|
||||||
|
|
||||||
if (!sock->driverdata)
|
if (!sock->driverdata)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -214,9 +239,14 @@ int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
|
||||||
// align
|
// align
|
||||||
buffer++;
|
buffer++;
|
||||||
|
|
||||||
|
*buffer++ = (sequence >> 0) & 0xff;
|
||||||
|
*buffer++ = (sequence >> 8) & 0xff;
|
||||||
|
*buffer++ = (sequence >> 16) & 0xff;
|
||||||
|
*buffer++ = (sequence >> 24) & 0xff;
|
||||||
|
|
||||||
// message
|
// message
|
||||||
Q_memcpy(buffer, data->data, data->cursize);
|
Q_memcpy(buffer, data->data, data->cursize);
|
||||||
*bufferLength = IntAlign(*bufferLength + data->cursize + 4);
|
*bufferLength = IntAlign(*bufferLength + data->cursize + 8);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
// net_loop.h
|
// net_loop.h
|
||||||
int Loop_Init (void);
|
int Loop_Init (void);
|
||||||
void Loop_Listen (qboolean state);
|
void Loop_Listen (qboolean state);
|
||||||
void Loop_SearchForHosts (qboolean xmit);
|
qboolean Loop_SearchForHosts (qboolean xmit);
|
||||||
qsocket_t *Loop_Connect (const char *host);
|
qsocket_t *Loop_Connect (const char *host);
|
||||||
qsocket_t *Loop_CheckNewConnections (void);
|
qsocket_t *Loop_CheckNewConnections (void);
|
||||||
|
qsocket_t *Loop_GetAnyMessage(void);
|
||||||
int Loop_GetMessage (qsocket_t *sock);
|
int Loop_GetMessage (qsocket_t *sock);
|
||||||
int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data);
|
int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data);
|
||||||
int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
|
int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
|
||||||
|
|
106
Quake/net_main.c
106
Quake/net_main.c
|
@ -30,20 +30,23 @@ qsocket_t *net_freeSockets = NULL;
|
||||||
int net_numsockets = 0;
|
int net_numsockets = 0;
|
||||||
|
|
||||||
qboolean ipxAvailable = false;
|
qboolean ipxAvailable = false;
|
||||||
qboolean tcpipAvailable = false;
|
qboolean ipv4Available = false;
|
||||||
|
qboolean ipv6Available = false;
|
||||||
|
|
||||||
int net_hostport;
|
int net_hostport;
|
||||||
int DEFAULTnet_hostport = 26000;
|
int DEFAULTnet_hostport = 26000;
|
||||||
|
|
||||||
char my_ipx_address[NET_NAMELEN];
|
char my_ipx_address[NET_NAMELEN];
|
||||||
char my_tcpip_address[NET_NAMELEN];
|
char my_ipv4_address[NET_NAMELEN];
|
||||||
|
char my_ipv6_address[NET_NAMELEN];
|
||||||
|
|
||||||
static qboolean listening = false;
|
static qboolean listening = false;
|
||||||
|
|
||||||
qboolean slistInProgress = false;
|
qboolean slistInProgress = false;
|
||||||
qboolean slistSilent = false;
|
qboolean slistSilent = false;
|
||||||
qboolean slistLocal = true;
|
enum slistScope_e slistScope = SLIST_LOOP;
|
||||||
static double slistStartTime;
|
static double slistStartTime;
|
||||||
|
static double slistActiveTime;
|
||||||
static int slistLastShown;
|
static int slistLastShown;
|
||||||
|
|
||||||
static void Slist_Send (void *);
|
static void Slist_Send (void *);
|
||||||
|
@ -59,7 +62,8 @@ int messagesReceived = 0;
|
||||||
int unreliableMessagesSent = 0;
|
int unreliableMessagesSent = 0;
|
||||||
int unreliableMessagesReceived = 0;
|
int unreliableMessagesReceived = 0;
|
||||||
|
|
||||||
static cvar_t net_messagetimeout = {"net_messagetimeout","300",CVAR_NONE};
|
cvar_t net_messagetimeout = {"net_messagetimeout","300",CVAR_NONE};
|
||||||
|
cvar_t net_connecttimeout = {"net_connecttimeout","10",CVAR_NONE}; //this might be a little brief, but we don't have a way to protect against smurf attacks.
|
||||||
cvar_t hostname = {"hostname", "UNNAMED", CVAR_NONE};
|
cvar_t hostname = {"hostname", "UNNAMED", CVAR_NONE};
|
||||||
|
|
||||||
// these two macros are to make the code more readable
|
// these two macros are to make the code more readable
|
||||||
|
@ -104,9 +108,11 @@ qsocket_t *NET_NewQSocket (void)
|
||||||
sock->next = net_activeSockets;
|
sock->next = net_activeSockets;
|
||||||
net_activeSockets = sock;
|
net_activeSockets = sock;
|
||||||
|
|
||||||
|
sock->isvirtual = false;
|
||||||
sock->disconnected = false;
|
sock->disconnected = false;
|
||||||
sock->connecttime = net_time;
|
sock->connecttime = net_time;
|
||||||
Q_strcpy (sock->address,"UNSET ADDRESS");
|
Q_strcpy (sock->trueaddress,"UNSET ADDRESS");
|
||||||
|
Q_strcpy (sock->maskedaddress,"UNSET ADDRESS");
|
||||||
sock->driver = net_driverlevel;
|
sock->driver = net_driverlevel;
|
||||||
sock->socket = 0;
|
sock->socket = 0;
|
||||||
sock->driverdata = NULL;
|
sock->driverdata = NULL;
|
||||||
|
@ -120,6 +126,8 @@ qsocket_t *NET_NewQSocket (void)
|
||||||
sock->receiveSequence = 0;
|
sock->receiveSequence = 0;
|
||||||
sock->unreliableReceiveSequence = 0;
|
sock->unreliableReceiveSequence = 0;
|
||||||
sock->receiveMessageLength = 0;
|
sock->receiveMessageLength = 0;
|
||||||
|
sock->pending_max_datagram = 1024;
|
||||||
|
sock->proquake_angle_hack = false;
|
||||||
|
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
@ -154,15 +162,38 @@ void NET_FreeQSocket(qsocket_t *sock)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int NET_QSocketGetSequenceIn (const qsocket_t *s)
|
||||||
|
{ //returns the last unreliable sequence that was received
|
||||||
|
return s->unreliableReceiveSequence-1;
|
||||||
|
}
|
||||||
|
int NET_QSocketGetSequenceOut (const qsocket_t *s)
|
||||||
|
{ //returns the next unreliable sequence that will be sent
|
||||||
|
return s->unreliableSendSequence;
|
||||||
|
}
|
||||||
double NET_QSocketGetTime (const qsocket_t *s)
|
double NET_QSocketGetTime (const qsocket_t *s)
|
||||||
{
|
{
|
||||||
return s->connecttime;
|
return s->connecttime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *NET_QSocketGetAddressString (const qsocket_t *s)
|
const char *NET_QSocketGetTrueAddressString (const qsocket_t *s)
|
||||||
{
|
{
|
||||||
return s->address;
|
return s->trueaddress;
|
||||||
|
}
|
||||||
|
const char *NET_QSocketGetMaskedAddressString (const qsocket_t *s)
|
||||||
|
{
|
||||||
|
return s->maskedaddress;
|
||||||
|
}
|
||||||
|
qboolean NET_QSocketGetProQuakeAngleHack(const qsocket_t *s)
|
||||||
|
{
|
||||||
|
if (s && !s->disconnected)
|
||||||
|
return s->proquake_angle_hack;
|
||||||
|
else
|
||||||
|
return false; //happens with demos
|
||||||
|
}
|
||||||
|
void NET_QSocketSetMSS(qsocket_t *s, int mss)
|
||||||
|
{
|
||||||
|
s->pending_max_datagram = mss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -263,7 +294,7 @@ static void PrintSlistHeader(void)
|
||||||
|
|
||||||
static void PrintSlist(void)
|
static void PrintSlist(void)
|
||||||
{
|
{
|
||||||
int n;
|
size_t n;
|
||||||
|
|
||||||
for (n = slistLastShown; n < hostCacheCount; n++)
|
for (n = slistLastShown; n < hostCacheCount; n++)
|
||||||
{
|
{
|
||||||
|
@ -297,7 +328,7 @@ void NET_Slist_f (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
slistInProgress = true;
|
slistInProgress = true;
|
||||||
slistStartTime = Sys_DoubleTime();
|
slistActiveTime = slistStartTime = Sys_DoubleTime();
|
||||||
|
|
||||||
SchedulePollProcedure(&slistSendProcedure, 0.0);
|
SchedulePollProcedure(&slistSendProcedure, 0.0);
|
||||||
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
||||||
|
@ -310,7 +341,7 @@ void NET_SlistSort (void)
|
||||||
{
|
{
|
||||||
if (hostCacheCount > 1)
|
if (hostCacheCount > 1)
|
||||||
{
|
{
|
||||||
int i, j;
|
size_t i, j;
|
||||||
hostcache_t temp;
|
hostcache_t temp;
|
||||||
for (i = 0; i < hostCacheCount; i++)
|
for (i = 0; i < hostCacheCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -328,11 +359,11 @@ void NET_SlistSort (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *NET_SlistPrintServer (int idx)
|
const char *NET_SlistPrintServer (size_t idx)
|
||||||
{
|
{
|
||||||
static char string[64];
|
static char string[64];
|
||||||
|
|
||||||
if (idx < 0 || idx >= hostCacheCount)
|
if (idx >= hostCacheCount)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
if (hostcache[idx].maxusers)
|
if (hostcache[idx].maxusers)
|
||||||
|
@ -351,9 +382,9 @@ const char *NET_SlistPrintServer (int idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *NET_SlistPrintServerName (int idx)
|
const char *NET_SlistPrintServerName (size_t idx)
|
||||||
{
|
{
|
||||||
if (idx < 0 || idx >= hostCacheCount)
|
if (idx >= hostCacheCount)
|
||||||
return "";
|
return "";
|
||||||
return hostcache[idx].cname;
|
return hostcache[idx].cname;
|
||||||
}
|
}
|
||||||
|
@ -363,7 +394,7 @@ static void Slist_Send (void *unused)
|
||||||
{
|
{
|
||||||
for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
|
||||||
{
|
{
|
||||||
if (!slistLocal && IS_LOOP_DRIVER(net_driverlevel))
|
if (slistScope!=SLIST_LOOP && IS_LOOP_DRIVER(net_driverlevel))
|
||||||
continue;
|
continue;
|
||||||
if (net_drivers[net_driverlevel].initialized == false)
|
if (net_drivers[net_driverlevel].initialized == false)
|
||||||
continue;
|
continue;
|
||||||
|
@ -379,17 +410,18 @@ static void Slist_Poll (void *unused)
|
||||||
{
|
{
|
||||||
for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
|
||||||
{
|
{
|
||||||
if (!slistLocal && IS_LOOP_DRIVER(net_driverlevel))
|
if (slistScope!=SLIST_LOOP && IS_LOOP_DRIVER(net_driverlevel))
|
||||||
continue;
|
continue;
|
||||||
if (net_drivers[net_driverlevel].initialized == false)
|
if (net_drivers[net_driverlevel].initialized == false)
|
||||||
continue;
|
continue;
|
||||||
dfunc.SearchForHosts (false);
|
if (dfunc.SearchForHosts (false))
|
||||||
|
slistActiveTime = Sys_DoubleTime(); //something was sent, reset the timer.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! slistSilent)
|
if (! slistSilent)
|
||||||
PrintSlist();
|
PrintSlist();
|
||||||
|
|
||||||
if ((Sys_DoubleTime() - slistStartTime) < 1.5)
|
if ((Sys_DoubleTime() - slistActiveTime) < 1.5)
|
||||||
{
|
{
|
||||||
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
||||||
return;
|
return;
|
||||||
|
@ -399,7 +431,7 @@ static void Slist_Poll (void *unused)
|
||||||
PrintSlistTrailer();
|
PrintSlistTrailer();
|
||||||
slistInProgress = false;
|
slistInProgress = false;
|
||||||
slistSilent = false;
|
slistSilent = false;
|
||||||
slistLocal = true;
|
slistScope = SLIST_LOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -409,13 +441,13 @@ NET_Connect
|
||||||
===================
|
===================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int hostCacheCount = 0;
|
size_t hostCacheCount = 0;
|
||||||
hostcache_t hostcache[HOSTCACHESIZE];
|
hostcache_t hostcache[HOSTCACHESIZE];
|
||||||
|
|
||||||
qsocket_t *NET_Connect (const char *host)
|
qsocket_t *NET_Connect (const char *host)
|
||||||
{
|
{
|
||||||
qsocket_t *ret;
|
qsocket_t *ret;
|
||||||
int n;
|
size_t n;
|
||||||
int numdrivers = net_numdrivers;
|
int numdrivers = net_numdrivers;
|
||||||
|
|
||||||
SetNetTime();
|
SetNetTime();
|
||||||
|
@ -594,6 +626,29 @@ int NET_GetMessage (qsocket_t *sock)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
NET_GetServerMessage
|
||||||
|
|
||||||
|
If there is a complete message, return it in net_message
|
||||||
|
|
||||||
|
returns the qsocket that the message was meant to be for.
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
qsocket_t *NET_GetServerMessage(void)
|
||||||
|
{
|
||||||
|
qsocket_t *s;
|
||||||
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
|
||||||
|
{
|
||||||
|
if (!net_drivers[net_driverlevel].initialized)
|
||||||
|
continue;
|
||||||
|
s = net_drivers[net_driverlevel].QGetAnyMessage();
|
||||||
|
if (s)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
|
@ -797,6 +852,7 @@ void NET_Init (void)
|
||||||
SZ_Alloc (&net_message, NET_MAXMESSAGE);
|
SZ_Alloc (&net_message, NET_MAXMESSAGE);
|
||||||
|
|
||||||
Cvar_RegisterVariable (&net_messagetimeout);
|
Cvar_RegisterVariable (&net_messagetimeout);
|
||||||
|
Cvar_RegisterVariable (&net_connecttimeout);
|
||||||
Cvar_RegisterVariable (&hostname);
|
Cvar_RegisterVariable (&hostname);
|
||||||
|
|
||||||
Cmd_AddCommand ("slist", NET_Slist_f);
|
Cmd_AddCommand ("slist", NET_Slist_f);
|
||||||
|
@ -828,9 +884,13 @@ void NET_Init (void)
|
||||||
{
|
{
|
||||||
Con_DPrintf("IPX address %s\n", my_ipx_address);
|
Con_DPrintf("IPX address %s\n", my_ipx_address);
|
||||||
}
|
}
|
||||||
if (*my_tcpip_address)
|
if (*my_ipv4_address)
|
||||||
{
|
{
|
||||||
Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
|
Con_DPrintf("IPv4 address %s\n", my_ipv4_address);
|
||||||
|
}
|
||||||
|
if (*my_ipv6_address)
|
||||||
|
{
|
||||||
|
Con_DPrintf("IPv6 address %s\n", my_ipv6_address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,9 +143,10 @@ COMPILE_TIME_ASSERT(sockaddr, offsetof(struct sockaddr, sa_family) == SA_FAM_OFF
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
|
|
||||||
/* NOTE: winsock[2].h already includes windows.h */
|
/* NOTE: winsock[2].h already includes windows.h */
|
||||||
#if !defined(_USE_WINSOCK2)
|
#if 0//!defined(_USE_WINSOCK2)
|
||||||
#include <winsock.h>
|
#include <winsock.h>
|
||||||
#else
|
#else
|
||||||
|
//winsock2 has been available since win98, and is available as a separate download for win95, which would be needed for any web browsers anyway.
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
569
Quake/net_udp.c
569
Quake/net_udp.c
|
@ -26,18 +26,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
#include "net_defs.h"
|
#include "net_defs.h"
|
||||||
|
|
||||||
static sys_socket_t net_acceptsocket = INVALID_SOCKET; // socket for fielding new connections
|
static sys_socket_t net_acceptsocket4 = INVALID_SOCKET; // socket for fielding new connections
|
||||||
static sys_socket_t net_controlsocket;
|
static sys_socket_t net_controlsocket4;
|
||||||
static sys_socket_t net_broadcastsocket = 0;
|
static sys_socket_t net_broadcastsocket4 = INVALID_SOCKET;
|
||||||
static struct sockaddr_in broadcastaddr;
|
static struct sockaddr_in broadcastaddr4;
|
||||||
|
|
||||||
static in_addr_t myAddr;
|
static in_addr_t myAddr4;
|
||||||
|
|
||||||
|
static sys_socket_t net_acceptsocket6 = INVALID_SOCKET; // socket for fielding new connections
|
||||||
|
static sys_socket_t net_controlsocket6;
|
||||||
|
|
||||||
|
static struct in6_addr myAddrv6;
|
||||||
|
|
||||||
#include "net_udp.h"
|
#include "net_udp.h"
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
sys_socket_t UDP_Init (void)
|
sys_socket_t UDP4_Init (void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char *tst;
|
char *tst;
|
||||||
|
@ -45,15 +50,15 @@ sys_socket_t UDP_Init (void)
|
||||||
struct hostent *local;
|
struct hostent *local;
|
||||||
struct qsockaddr addr;
|
struct qsockaddr addr;
|
||||||
|
|
||||||
if (COM_CheckParm ("-noudp"))
|
if (COM_CheckParm ("-noudp") || COM_CheckParm ("-noudp4"))
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
|
|
||||||
// determine my name & address
|
// determine my name & address
|
||||||
myAddr = htonl(INADDR_LOOPBACK);
|
myAddr4 = htonl(INADDR_LOOPBACK);
|
||||||
if (gethostname(buff, MAXHOSTNAMELEN) != 0)
|
if (gethostname(buff, MAXHOSTNAMELEN) != 0)
|
||||||
{
|
{
|
||||||
err = SOCKETERRNO;
|
err = SOCKETERRNO;
|
||||||
Con_SafePrintf("UDP_Init: gethostname failed (%s)\n",
|
Con_SafePrintf("UDP4_Init: gethostname failed (%s)\n",
|
||||||
socketerror(err));
|
socketerror(err));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -72,72 +77,76 @@ sys_socket_t UDP_Init (void)
|
||||||
#endif
|
#endif
|
||||||
if (!(local = gethostbyname(buff)))
|
if (!(local = gethostbyname(buff)))
|
||||||
{
|
{
|
||||||
Con_SafePrintf("UDP_Init: gethostbyname failed (%s)\n",
|
Con_SafePrintf("UDP4_Init: gethostbyname failed (%s)\n",
|
||||||
hstrerror(h_errno));
|
hstrerror(h_errno));
|
||||||
}
|
}
|
||||||
else if (local->h_addrtype != AF_INET)
|
else if (local->h_addrtype != AF_INET)
|
||||||
{
|
{
|
||||||
Con_SafePrintf("UDP_Init: address from gethostbyname not IPv4\n");
|
Con_SafePrintf("UDP4_Init: address from gethostbyname not IPv4\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
myAddr = *(in_addr_t *)local->h_addr_list[0];
|
myAddr4 = *(in_addr_t *)local->h_addr_list[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((net_controlsocket = UDP_OpenSocket(0)) == INVALID_SOCKET)
|
if ((net_controlsocket4 = UDP4_OpenSocket(0)) == INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
Con_SafePrintf("UDP_Init: Unable to open control socket, UDP disabled\n");
|
Con_SafePrintf("UDP4_Init: Unable to open control socket, UDP disabled\n");
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastaddr.sin_family = AF_INET;
|
broadcastaddr4.sin_family = AF_INET;
|
||||||
broadcastaddr.sin_addr.s_addr = INADDR_BROADCAST;
|
broadcastaddr4.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
broadcastaddr.sin_port = htons((unsigned short)net_hostport);
|
broadcastaddr4.sin_port = htons((unsigned short)net_hostport);
|
||||||
|
|
||||||
UDP_GetSocketAddr (net_controlsocket, &addr);
|
UDP_GetSocketAddr (net_controlsocket4, &addr);
|
||||||
strcpy(my_tcpip_address, UDP_AddrToString (&addr));
|
strcpy(my_ipv4_address, UDP_AddrToString (&addr, false));
|
||||||
tst = strrchr(my_tcpip_address, ':');
|
tst = strrchr (my_ipv4_address, ':');
|
||||||
if (tst) *tst = 0;
|
if (tst) *tst = 0;
|
||||||
|
|
||||||
Con_SafePrintf("UDP Initialized\n");
|
Con_SafePrintf("UDP4 Initialized\n");
|
||||||
tcpipAvailable = true;
|
ipv4Available = true;
|
||||||
|
|
||||||
return net_controlsocket;
|
return net_controlsocket4;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void UDP_Shutdown (void)
|
void UDP4_Shutdown (void)
|
||||||
{
|
{
|
||||||
UDP_Listen (false);
|
UDP4_Listen (false);
|
||||||
UDP_CloseSocket (net_controlsocket);
|
UDP_CloseSocket (net_controlsocket4);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void UDP_Listen (qboolean state)
|
sys_socket_t UDP4_Listen (qboolean state)
|
||||||
{
|
{
|
||||||
// enable listening
|
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
if (net_acceptsocket != INVALID_SOCKET)
|
// enable listening
|
||||||
return;
|
if (net_acceptsocket4 == INVALID_SOCKET)
|
||||||
if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == INVALID_SOCKET)
|
{
|
||||||
Sys_Error ("UDP_Listen: Unable to open accept socket");
|
if ((net_acceptsocket4 = UDP4_OpenSocket (net_hostport)) == INVALID_SOCKET)
|
||||||
return;
|
Sys_Error ("UDP4_Listen: Unable to open accept socket");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// disable listening
|
{
|
||||||
if (net_acceptsocket == INVALID_SOCKET)
|
// disable listening
|
||||||
return;
|
if (net_acceptsocket4 != INVALID_SOCKET)
|
||||||
UDP_CloseSocket (net_acceptsocket);
|
{
|
||||||
net_acceptsocket = INVALID_SOCKET;
|
UDP_CloseSocket (net_acceptsocket4);
|
||||||
|
net_acceptsocket4 = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return net_acceptsocket4;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
sys_socket_t UDP_OpenSocket (int port)
|
sys_socket_t UDP4_OpenSocket (int port)
|
||||||
{
|
{
|
||||||
sys_socket_t newsocket;
|
sys_socket_t newsocket;
|
||||||
struct sockaddr_in address;
|
struct sockaddr_in address;
|
||||||
|
@ -147,7 +156,7 @@ sys_socket_t UDP_OpenSocket (int port)
|
||||||
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
err = SOCKETERRNO;
|
err = SOCKETERRNO;
|
||||||
Con_SafePrintf("UDP_OpenSocket: %s\n", socketerror(err));
|
Con_SafePrintf("UDP4_OpenSocket: %s\n", socketerror(err));
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +172,7 @@ sys_socket_t UDP_OpenSocket (int port)
|
||||||
|
|
||||||
ErrorReturn:
|
ErrorReturn:
|
||||||
err = SOCKETERRNO;
|
err = SOCKETERRNO;
|
||||||
Con_SafePrintf("UDP_OpenSocket: %s\n", socketerror(err));
|
Con_SafePrintf("UDP4_OpenSocket: %s\n", socketerror(err));
|
||||||
UDP_CloseSocket (newsocket);
|
UDP_CloseSocket (newsocket);
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
@ -172,8 +181,8 @@ ErrorReturn:
|
||||||
|
|
||||||
int UDP_CloseSocket (sys_socket_t socketid)
|
int UDP_CloseSocket (sys_socket_t socketid)
|
||||||
{
|
{
|
||||||
if (socketid == net_broadcastsocket)
|
if (socketid == net_broadcastsocket4)
|
||||||
net_broadcastsocket = 0;
|
net_broadcastsocket4 = INVALID_SOCKET;
|
||||||
return closesocket (socketid);
|
return closesocket (socketid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +237,7 @@ static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr)
|
||||||
hostaddr->qsa_family = AF_INET;
|
hostaddr->qsa_family = AF_INET;
|
||||||
((struct sockaddr_in *)hostaddr)->sin_port = htons((unsigned short)port);
|
((struct sockaddr_in *)hostaddr)->sin_port = htons((unsigned short)port);
|
||||||
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr =
|
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr =
|
||||||
(myAddr & htonl(mask)) | htonl(addr);
|
(myAddr4 & htonl(mask)) | htonl(addr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -242,25 +251,25 @@ int UDP_Connect (sys_socket_t socketid, struct qsockaddr *addr)
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
sys_socket_t UDP_CheckNewConnections (void)
|
sys_socket_t UDP4_CheckNewConnections (void)
|
||||||
{
|
{
|
||||||
int available;
|
int available;
|
||||||
struct sockaddr_in from;
|
struct sockaddr_in from;
|
||||||
socklen_t fromlen;
|
socklen_t fromlen;
|
||||||
char buff[1];
|
char buff[1];
|
||||||
|
|
||||||
if (net_acceptsocket == INVALID_SOCKET)
|
if (net_acceptsocket4 == INVALID_SOCKET)
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
|
|
||||||
if (ioctl (net_acceptsocket, FIONREAD, &available) == -1)
|
if (ioctl (net_acceptsocket4, FIONREAD, &available) == -1)
|
||||||
{
|
{
|
||||||
int err = SOCKETERRNO;
|
int err = SOCKETERRNO;
|
||||||
Sys_Error ("UDP: ioctlsocket (FIONREAD) failed (%s)", socketerror(err));
|
Sys_Error ("UDP: ioctlsocket (FIONREAD) failed (%s)", socketerror(err));
|
||||||
}
|
}
|
||||||
if (available)
|
if (available)
|
||||||
return net_acceptsocket;
|
return net_acceptsocket4;
|
||||||
// quietly absorb empty packets
|
// quietly absorb empty packets
|
||||||
recvfrom (net_acceptsocket, buff, 0, 0, (struct sockaddr *) &from, &fromlen);
|
recvfrom (net_acceptsocket4, buff, 0, 0, (struct sockaddr *) &from, &fromlen);
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +293,7 @@ int UDP_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr)
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
static int UDP_MakeSocketBroadcastCapable (sys_socket_t socketid)
|
static int UDP4_MakeSocketBroadcastCapable (sys_socket_t socketid)
|
||||||
{
|
{
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
|
@ -296,30 +305,30 @@ static int UDP_MakeSocketBroadcastCapable (sys_socket_t socketid)
|
||||||
Con_SafePrintf ("UDP, setsockopt: %s\n", socketerror(err));
|
Con_SafePrintf ("UDP, setsockopt: %s\n", socketerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
net_broadcastsocket = socketid;
|
net_broadcastsocket4 = socketid;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int UDP_Broadcast (sys_socket_t socketid, byte *buf, int len)
|
int UDP4_Broadcast (sys_socket_t socketid, byte *buf, int len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (socketid != net_broadcastsocket)
|
if (socketid != net_broadcastsocket4)
|
||||||
{
|
{
|
||||||
if (net_broadcastsocket != 0)
|
if (net_broadcastsocket4 != INVALID_SOCKET)
|
||||||
Sys_Error("Attempted to use multiple broadcasts sockets");
|
Sys_Error("Attempted to use multiple broadcasts sockets");
|
||||||
ret = UDP_MakeSocketBroadcastCapable (socketid);
|
ret = UDP4_MakeSocketBroadcastCapable (socketid);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
Con_Printf("Unable to make socket broadcast capable\n");
|
Con_SafePrintf("Unable to make socket broadcast capable\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return UDP_Write (socketid, buf, len, (struct qsockaddr *)&broadcastaddr);
|
return UDP_Write (socketid, buf, len, (struct qsockaddr *)&broadcastaddr4);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -327,36 +336,86 @@ int UDP_Broadcast (sys_socket_t socketid, byte *buf, int len)
|
||||||
int UDP_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr)
|
int UDP_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
socklen_t addrsize;
|
||||||
|
if (addr->qsa_family == AF_INET)
|
||||||
|
addrsize = sizeof(struct sockaddr_in);
|
||||||
|
else if (addr->qsa_family == AF_INET6)
|
||||||
|
addrsize = sizeof(struct sockaddr_in6);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_SafePrintf ("UDP_Write: unknown family\n");
|
||||||
|
return -1; //some kind of error. a few systems get pissy if the size doesn't exactly match the address family
|
||||||
|
}
|
||||||
|
|
||||||
ret = sendto (socketid, buf, len, 0, (struct sockaddr *)addr,
|
ret = sendto (socketid, buf, len, 0, (struct sockaddr *)addr, addrsize);
|
||||||
sizeof(struct qsockaddr));
|
if (!addr->qsa_family)
|
||||||
|
Con_SafePrintf ("UDP_Write: family was cleared\n");
|
||||||
if (ret == SOCKET_ERROR)
|
if (ret == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
int err = SOCKETERRNO;
|
int err = SOCKETERRNO;
|
||||||
if (err == NET_EWOULDBLOCK)
|
if (err == NET_EWOULDBLOCK)
|
||||||
return 0;
|
return 0;
|
||||||
Con_SafePrintf ("UDP_Write, sendto: %s\n", socketerror(err));
|
if (err == ENETUNREACH)
|
||||||
|
Con_SafePrintf ("UDP_Write: %s (%s)\n", socketerror(err), UDP_AddrToString(addr, false));
|
||||||
|
else
|
||||||
|
Con_SafePrintf ("UDP_Write, sendto: %s\n", socketerror(err));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
const char *UDP_AddrToString (struct qsockaddr *addr)
|
const char *UDP_AddrToString (struct qsockaddr *addr, qboolean masked)
|
||||||
{
|
{
|
||||||
static char buffer[22];
|
static char buffer[64];
|
||||||
int haddr;
|
|
||||||
|
|
||||||
haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
if (addr->qsa_family == AF_INET)
|
||||||
q_snprintf (buffer, sizeof(buffer), "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff,
|
{
|
||||||
(haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff,
|
int haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
||||||
ntohs(((struct sockaddr_in *)addr)->sin_port));
|
q_snprintf (buffer, sizeof(buffer), "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff,
|
||||||
|
(haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff,
|
||||||
|
ntohs(((struct sockaddr_in *)addr)->sin_port));
|
||||||
|
}
|
||||||
|
else if (addr->qsa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
//evil type punning.
|
||||||
|
unsigned short *s = (unsigned short*)&((struct sockaddr_in6 *)addr)->sin6_addr;
|
||||||
|
if (((struct sockaddr_in6 *)addr)->sin6_scope_id)
|
||||||
|
{
|
||||||
|
q_snprintf(buffer, sizeof(buffer), "[%x:%x:%x:%x:%x:%x:%x:%x%%%i]:%d",
|
||||||
|
ntohs(s[0]),
|
||||||
|
ntohs(s[1]),
|
||||||
|
ntohs(s[2]),
|
||||||
|
ntohs(s[3]),
|
||||||
|
ntohs(s[4]),
|
||||||
|
ntohs(s[5]),
|
||||||
|
ntohs(s[6]),
|
||||||
|
ntohs(s[7]),
|
||||||
|
(int)((struct sockaddr_in6 *)addr)->sin6_scope_id,
|
||||||
|
ntohs(((struct sockaddr_in6 *)addr)->sin6_port));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
q_snprintf(buffer, sizeof(buffer), "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
|
||||||
|
ntohs(s[0]),
|
||||||
|
ntohs(s[1]),
|
||||||
|
ntohs(s[2]),
|
||||||
|
ntohs(s[3]),
|
||||||
|
ntohs(s[4]),
|
||||||
|
ntohs(s[5]),
|
||||||
|
ntohs(s[6]),
|
||||||
|
ntohs(s[7]),
|
||||||
|
ntohs(((struct sockaddr_in6 *)addr)->sin6_port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strcpy(buffer, "?");
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int UDP_StringToAddr (const char *string, struct qsockaddr *addr)
|
int UDP4_StringToAddr (const char *string, struct qsockaddr *addr)
|
||||||
{
|
{
|
||||||
int ha1, ha2, ha3, ha4, hp, ipaddr;
|
int ha1, ha2, ha3, ha4, hp, ipaddr;
|
||||||
|
|
||||||
|
@ -380,9 +439,18 @@ int UDP_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr)
|
||||||
if (getsockname(socketid, (struct sockaddr *)addr, &addrlen) != 0)
|
if (getsockname(socketid, (struct sockaddr *)addr, &addrlen) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
if (addr->qsa_family == AF_INET)
|
||||||
if (a == 0 || a == htonl(INADDR_LOOPBACK))
|
{
|
||||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
|
a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
||||||
|
if (a == 0 || a == htonl(INADDR_LOOPBACK))
|
||||||
|
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr4;
|
||||||
|
}
|
||||||
|
else if (addr->qsa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
|
||||||
|
if (!memcmp(&((struct sockaddr_in6 *)addr)->sin6_addr, &in6addr_any, sizeof(in6addr_any)))
|
||||||
|
memcpy(&((struct sockaddr_in6 *)addr)->sin6_addr, &myAddrv6, sizeof(((struct sockaddr_in6 *)addr)->sin6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -391,35 +459,56 @@ int UDP_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr)
|
||||||
|
|
||||||
int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
||||||
{
|
{
|
||||||
struct hostent *hostentry;
|
if (addr->qsa_family == AF_INET)
|
||||||
|
|
||||||
hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr,
|
|
||||||
sizeof(struct in_addr), AF_INET);
|
|
||||||
if (hostentry)
|
|
||||||
{
|
{
|
||||||
strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
|
struct hostent *hostentry;
|
||||||
return 0;
|
|
||||||
|
hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr,
|
||||||
|
sizeof(struct in_addr), AF_INET);
|
||||||
|
if (hostentry)
|
||||||
|
{
|
||||||
|
strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addr->qsa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
//meh, don't bother, its unreliable anyway.
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy (name, UDP_AddrToString (addr));
|
strcpy (name, UDP_AddrToString (addr, false));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int UDP_GetAddrFromName (const char *name, struct qsockaddr *addr)
|
int UDP4_GetAddrFromName (const char *name, struct qsockaddr *addr)
|
||||||
{
|
{
|
||||||
struct hostent *hostentry;
|
struct hostent *hostentry;
|
||||||
|
char *colon;
|
||||||
|
unsigned short port = net_hostport;
|
||||||
|
|
||||||
if (name[0] >= '0' && name[0] <= '9')
|
if (name[0] >= '0' && name[0] <= '9')
|
||||||
return PartialIPAddress (name, addr);
|
return PartialIPAddress (name, addr);
|
||||||
|
|
||||||
hostentry = gethostbyname (name);
|
colon = strrchr(name, ':');
|
||||||
if (!hostentry)
|
if (colon)
|
||||||
|
{
|
||||||
|
char dupe[MAXHOSTNAMELEN];
|
||||||
|
if (colon-name+1 > MAXHOSTNAMELEN)
|
||||||
|
return -1;
|
||||||
|
memcpy(dupe, name, colon-name);
|
||||||
|
dupe[colon-name] = 0;
|
||||||
|
hostentry = gethostbyname (dupe);
|
||||||
|
port = strtoul(colon+1, NULL, 10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hostentry = gethostbyname (name);
|
||||||
|
if (!hostentry || hostentry->h_addrtype != AF_INET)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
addr->qsa_family = AF_INET;
|
addr->qsa_family = AF_INET;
|
||||||
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);
|
((struct sockaddr_in *)addr)->sin_port = htons(port);
|
||||||
((struct sockaddr_in *)addr)->sin_addr.s_addr =
|
((struct sockaddr_in *)addr)->sin_addr.s_addr =
|
||||||
*(in_addr_t *)hostentry->h_addr_list[0];
|
*(in_addr_t *)hostentry->h_addr_list[0];
|
||||||
|
|
||||||
|
@ -433,30 +522,322 @@ int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||||
if (addr1->qsa_family != addr2->qsa_family)
|
if (addr1->qsa_family != addr2->qsa_family)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (((struct sockaddr_in *)addr1)->sin_addr.s_addr !=
|
if (addr1->qsa_family == AF_INET)
|
||||||
((struct sockaddr_in *)addr2)->sin_addr.s_addr)
|
{
|
||||||
|
if (((struct sockaddr_in *)addr1)->sin_addr.s_addr !=
|
||||||
|
((struct sockaddr_in *)addr2)->sin_addr.s_addr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (((struct sockaddr_in *)addr1)->sin_port !=
|
||||||
|
((struct sockaddr_in *)addr2)->sin_port)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (addr1->qsa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
if (memcmp( &((struct sockaddr_in6 *)addr1)->sin6_addr,
|
||||||
|
&((struct sockaddr_in6 *)addr2)->sin6_addr,
|
||||||
|
sizeof(((struct sockaddr_in6 *)addr1)->sin6_addr)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (((struct sockaddr_in6 *)addr1)->sin6_port !=
|
||||||
|
((struct sockaddr_in6 *)addr2)->sin6_port)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (((struct sockaddr_in6 *)addr1)->sin6_scope_id &&
|
||||||
|
((struct sockaddr_in6 *)addr2)->sin6_scope_id &&
|
||||||
|
((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
|
||||||
|
((struct sockaddr_in6 *)addr2)->sin6_scope_id) //the ipv6 scope id is for use with link-local addresses, to identify the specific interface.
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (((struct sockaddr_in *)addr1)->sin_port !=
|
|
||||||
((struct sockaddr_in *)addr2)->sin_port)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int UDP_GetSocketPort (struct qsockaddr *addr)
|
int UDP_GetSocketPort (struct qsockaddr *addr)
|
||||||
{
|
{
|
||||||
return ntohs(((struct sockaddr_in *)addr)->sin_port);
|
if (addr->qsa_family == AF_INET)
|
||||||
|
return ntohs(((struct sockaddr_in *)addr)->sin_port);
|
||||||
|
else if (addr->qsa_family == AF_INET6)
|
||||||
|
return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int UDP_SetSocketPort (struct qsockaddr *addr, int port)
|
int UDP_SetSocketPort (struct qsockaddr *addr, int port)
|
||||||
{
|
{
|
||||||
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
|
if (addr->qsa_family == AF_INET)
|
||||||
|
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
|
||||||
|
else if (addr->qsa_family == AF_INET6)
|
||||||
|
((struct sockaddr_in6 *)addr)->sin6_port = htons((unsigned short)port);
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sys_socket_t UDP6_Init (void)
|
||||||
|
{
|
||||||
|
char *colon;
|
||||||
|
struct qsockaddr addr;
|
||||||
|
|
||||||
|
if (COM_CheckParm ("-noudp") || COM_CheckParm ("-noudp6"))
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
|
||||||
|
// TODO: determine my name & address
|
||||||
|
|
||||||
|
if ((net_controlsocket6 = UDP6_OpenSocket(0)) == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
Con_SafePrintf("UDP6_Init: Unable to open control socket, UDPv6 disabled\n");
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
UDP_GetSocketAddr (net_controlsocket6, &addr);
|
||||||
|
strcpy(my_ipv6_address, UDP_AddrToString (&addr, false));
|
||||||
|
colon = strrchr (my_ipv6_address, ':');
|
||||||
|
if (colon)
|
||||||
|
*colon = 0;
|
||||||
|
|
||||||
|
Con_SafePrintf("UDPv6 Initialized\n");
|
||||||
|
ipv6Available = true;
|
||||||
|
|
||||||
|
return net_controlsocket6;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
void UDP6_Shutdown (void)
|
||||||
|
{
|
||||||
|
UDP6_Listen (false);
|
||||||
|
UDP_CloseSocket (net_controlsocket6);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
sys_socket_t UDP6_Listen (qboolean state)
|
||||||
|
{
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
// enable listening
|
||||||
|
if (net_acceptsocket6 == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
if ((net_acceptsocket6 = UDP6_OpenSocket (net_hostport)) == INVALID_SOCKET)
|
||||||
|
Sys_Error ("UDP6_Listen: Unable to open accept socket");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// disable listening
|
||||||
|
if (net_acceptsocket6 != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
UDP_CloseSocket (net_acceptsocket6);
|
||||||
|
net_acceptsocket6 = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return net_acceptsocket6;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
sys_socket_t UDP6_OpenSocket (int port)
|
||||||
|
{
|
||||||
|
sys_socket_t newsocket;
|
||||||
|
struct sockaddr_in6 address;
|
||||||
|
int _true = 1;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((newsocket = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
err = SOCKETERRNO;
|
||||||
|
Con_SafePrintf("UDP6_OpenSocket: %s\n", socketerror(err));
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&_true, sizeof(_true));
|
||||||
|
|
||||||
|
if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR)
|
||||||
|
goto ErrorReturn;
|
||||||
|
|
||||||
|
memset(&address, 0, sizeof(struct sockaddr_in6));
|
||||||
|
address.sin6_family = AF_INET6;
|
||||||
|
memset(&address.sin6_addr, 0, sizeof(address.sin6_addr));
|
||||||
|
address.sin6_port = htons((unsigned short)port);
|
||||||
|
if (bind (newsocket, (struct sockaddr *)&address, sizeof(address)) == 0)
|
||||||
|
{
|
||||||
|
//we don't know if we're the server or not. oh well.
|
||||||
|
struct ipv6_mreq req;
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
req.ipv6mr_multiaddr.s6_addr[0] = 0xff;
|
||||||
|
req.ipv6mr_multiaddr.s6_addr[1] = 0x03;
|
||||||
|
req.ipv6mr_multiaddr.s6_addr[15] = 0x01;
|
||||||
|
req.ipv6mr_interface = 0;
|
||||||
|
setsockopt(newsocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&req, sizeof(req));
|
||||||
|
|
||||||
|
return newsocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorReturn:
|
||||||
|
err = SOCKETERRNO;
|
||||||
|
Con_SafePrintf("UDP6_OpenSocket: %s\n", socketerror(err));
|
||||||
|
UDP_CloseSocket (newsocket);
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
sys_socket_t UDP6_CheckNewConnections (void)
|
||||||
|
{
|
||||||
|
int available;
|
||||||
|
struct sockaddr_in from;
|
||||||
|
socklen_t fromlen;
|
||||||
|
char buff[1];
|
||||||
|
|
||||||
|
if (net_acceptsocket6 == INVALID_SOCKET)
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
|
||||||
|
if (ioctl (net_acceptsocket6, FIONREAD, &available) == -1)
|
||||||
|
{
|
||||||
|
int err = SOCKETERRNO;
|
||||||
|
Sys_Error ("UDP6: ioctlsocket (FIONREAD) failed (%s)", socketerror(err));
|
||||||
|
}
|
||||||
|
if (available)
|
||||||
|
return net_acceptsocket6;
|
||||||
|
// quietly absorb empty packets
|
||||||
|
fromlen = sizeof(from);
|
||||||
|
recvfrom (net_acceptsocket6, buff, 0, 0, (struct sockaddr *) &from, &fromlen);
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
int UDP6_Broadcast (sys_socket_t socketid, byte *buf, int len)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 address;
|
||||||
|
|
||||||
|
memset(&address, 0, sizeof(struct sockaddr_in6));
|
||||||
|
address.sin6_family = AF_INET6;
|
||||||
|
memset(&address.sin6_addr, 0, sizeof(address.sin6_addr));
|
||||||
|
address.sin6_addr.s6_addr[0] = 0xff;
|
||||||
|
address.sin6_addr.s6_addr[1] = 0x03;
|
||||||
|
address.sin6_addr.s6_addr[15] = 0x1;
|
||||||
|
address.sin6_port = htons((unsigned short)net_hostport);
|
||||||
|
|
||||||
|
return UDP_Write (socketid, buf, len, (struct qsockaddr *)&address);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
int UDP6_StringToAddr (const char *string, struct qsockaddr *addr)
|
||||||
|
{ //This is never actually called...
|
||||||
|
Con_SafePrintf("UDP6_StringToAddr: %s\n", string);
|
||||||
|
return UDP6_GetAddrFromName(string, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
int UDP6_GetAddrFromName (const char *name, struct qsockaddr *addr)
|
||||||
|
{
|
||||||
|
struct addrinfo *addrinfo = NULL;
|
||||||
|
struct addrinfo *pos;
|
||||||
|
struct addrinfo udp6hint;
|
||||||
|
int error;
|
||||||
|
char *port;
|
||||||
|
char dupbase[256];
|
||||||
|
size_t len;
|
||||||
|
qboolean success = false;
|
||||||
|
|
||||||
|
memset(&udp6hint, 0, sizeof(udp6hint));
|
||||||
|
udp6hint.ai_family = 0;//Any... we check for AF_INET6 or 4
|
||||||
|
udp6hint.ai_socktype = SOCK_DGRAM;
|
||||||
|
udp6hint.ai_protocol = IPPROTO_UDP;
|
||||||
|
|
||||||
|
if (*name == '[')
|
||||||
|
{
|
||||||
|
port = strstr(name, "]");
|
||||||
|
if (!port)
|
||||||
|
error = EAI_NONAME;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len = port - (name+1);
|
||||||
|
if (len >= sizeof(dupbase))
|
||||||
|
len = sizeof(dupbase)-1;
|
||||||
|
strncpy(dupbase, name+1, len);
|
||||||
|
dupbase[len] = '\0';
|
||||||
|
error = getaddrinfo(dupbase, (port[1] == ':')?port+2:NULL, &udp6hint, &addrinfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port = strrchr(name, ':');
|
||||||
|
|
||||||
|
if (port)
|
||||||
|
{
|
||||||
|
len = port - name;
|
||||||
|
if (len >= sizeof(dupbase))
|
||||||
|
len = sizeof(dupbase)-1;
|
||||||
|
strncpy(dupbase, name, len);
|
||||||
|
dupbase[len] = '\0';
|
||||||
|
error = getaddrinfo(dupbase, port+1, &udp6hint, &addrinfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = EAI_NONAME;
|
||||||
|
if (error) //failed, try string with no port.
|
||||||
|
error = getaddrinfo(name, NULL, &udp6hint, &addrinfo); //remember, this func will return any address family that could be using the udp protocol... (ip4 or ip6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
((struct sockaddr*)addr)->sa_family = 0;
|
||||||
|
for (pos = addrinfo; pos; pos = pos->ai_next)
|
||||||
|
{
|
||||||
|
if (0)//pos->ai_family == AF_INET)
|
||||||
|
{
|
||||||
|
memcpy(addr, pos->ai_addr, pos->ai_addrlen);
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pos->ai_family == AF_INET6 && !success)
|
||||||
|
{
|
||||||
|
memcpy(addr, pos->ai_addr, pos->ai_addrlen);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeaddrinfo (addrinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
if (((struct sockaddr*)addr)->sa_family == AF_INET)
|
||||||
|
{
|
||||||
|
if (!((struct sockaddr_in *)addr)->sin_port)
|
||||||
|
((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);
|
||||||
|
}
|
||||||
|
else if (((struct sockaddr*)addr)->sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
if (!((struct sockaddr_in6 *)addr)->sin6_port)
|
||||||
|
((struct sockaddr_in6 *)addr)->sin6_port = htons(net_hostport);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
|
|
@ -22,21 +22,40 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#ifndef __net_udp_h
|
#ifndef __net_udp_h
|
||||||
#define __net_udp_h
|
#define __net_udp_h
|
||||||
|
|
||||||
sys_socket_t UDP_Init (void);
|
sys_socket_t UDP4_Init (void);
|
||||||
void UDP_Shutdown (void);
|
void UDP4_Shutdown (void);
|
||||||
void UDP_Listen (qboolean state);
|
sys_socket_t UDP4_Listen (qboolean state);
|
||||||
sys_socket_t UDP_OpenSocket (int port);
|
sys_socket_t UDP4_OpenSocket (int port);
|
||||||
int UDP_CloseSocket (sys_socket_t socketid);
|
int UDP_CloseSocket (sys_socket_t socketid);
|
||||||
int UDP_Connect (sys_socket_t socketid, struct qsockaddr *addr);
|
int UDP_Connect (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
sys_socket_t UDP_CheckNewConnections (void);
|
sys_socket_t UDP4_CheckNewConnections (void);
|
||||||
int UDP_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
int UDP_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
int UDP_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
int UDP_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
int UDP_Broadcast (sys_socket_t socketid, byte *buf, int len);
|
int UDP4_Broadcast (sys_socket_t socketid, byte *buf, int len);
|
||||||
const char *UDP_AddrToString (struct qsockaddr *addr);
|
const char *UDP_AddrToString (struct qsockaddr *addr, qboolean masked);
|
||||||
int UDP_StringToAddr (const char *string, struct qsockaddr *addr);
|
int UDP4_StringToAddr (const char *string, struct qsockaddr *addr);
|
||||||
int UDP_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr);
|
int UDP_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
||||||
int UDP_GetAddrFromName (const char *name, struct qsockaddr *addr);
|
int UDP4_GetAddrFromName (const char *name, struct qsockaddr *addr);
|
||||||
|
int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||||
|
int UDP_GetSocketPort (struct qsockaddr *addr);
|
||||||
|
int UDP_SetSocketPort (struct qsockaddr *addr, int port);
|
||||||
|
|
||||||
|
sys_socket_t UDP6_Init (void);
|
||||||
|
void UDP6_Shutdown (void);
|
||||||
|
sys_socket_t UDP6_Listen (qboolean state);
|
||||||
|
sys_socket_t UDP6_OpenSocket (int port);
|
||||||
|
int UDP_CloseSocket (sys_socket_t socketid);
|
||||||
|
int UDP_Connect (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
|
sys_socket_t UDP6_CheckNewConnections (void);
|
||||||
|
int UDP_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
|
int UDP_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
|
int UDP6_Broadcast (sys_socket_t socketid, byte *buf, int len);
|
||||||
|
const char *UDP_AddrToString (struct qsockaddr *addr, qboolean masked);
|
||||||
|
int UDP6_StringToAddr (const char *string, struct qsockaddr *addr);
|
||||||
|
int UDP_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
|
int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
||||||
|
int UDP6_GetAddrFromName (const char *name, struct qsockaddr *addr);
|
||||||
int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||||
int UDP_GetSocketPort (struct qsockaddr *addr);
|
int UDP_GetSocketPort (struct qsockaddr *addr);
|
||||||
int UDP_SetSocketPort (struct qsockaddr *addr, int port);
|
int UDP_SetSocketPort (struct qsockaddr *addr, int port);
|
||||||
|
|
|
@ -37,6 +37,7 @@ net_driver_t net_drivers[] =
|
||||||
Loop_SearchForHosts,
|
Loop_SearchForHosts,
|
||||||
Loop_Connect,
|
Loop_Connect,
|
||||||
Loop_CheckNewConnections,
|
Loop_CheckNewConnections,
|
||||||
|
Loop_GetAnyMessage,
|
||||||
Loop_GetMessage,
|
Loop_GetMessage,
|
||||||
Loop_SendMessage,
|
Loop_SendMessage,
|
||||||
Loop_SendUnreliableMessage,
|
Loop_SendUnreliableMessage,
|
||||||
|
@ -53,6 +54,7 @@ net_driver_t net_drivers[] =
|
||||||
Datagram_SearchForHosts,
|
Datagram_SearchForHosts,
|
||||||
Datagram_Connect,
|
Datagram_Connect,
|
||||||
Datagram_CheckNewConnections,
|
Datagram_CheckNewConnections,
|
||||||
|
Datagram_GetAnyMessage,
|
||||||
Datagram_GetMessage,
|
Datagram_GetMessage,
|
||||||
Datagram_SendMessage,
|
Datagram_SendMessage,
|
||||||
Datagram_SendUnreliableMessage,
|
Datagram_SendUnreliableMessage,
|
||||||
|
@ -74,26 +76,49 @@ net_landriver_t net_landrivers[] =
|
||||||
{ "Winsock TCPIP",
|
{ "Winsock TCPIP",
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
WINS_Init,
|
WINIPv4_Init,
|
||||||
WINS_Shutdown,
|
WINIPv4_Shutdown,
|
||||||
WINS_Listen,
|
WINIPv4_Listen,
|
||||||
WINS_OpenSocket,
|
WINIPv4_OpenSocket,
|
||||||
WINS_CloseSocket,
|
WINS_CloseSocket,
|
||||||
WINS_Connect,
|
WINS_Connect,
|
||||||
WINS_CheckNewConnections,
|
WINIPv4_CheckNewConnections,
|
||||||
WINS_Read,
|
WINS_Read,
|
||||||
WINS_Write,
|
WINS_Write,
|
||||||
WINS_Broadcast,
|
WINIPv4_Broadcast,
|
||||||
WINS_AddrToString,
|
WINS_AddrToString,
|
||||||
WINS_StringToAddr,
|
WINIPv4_StringToAddr,
|
||||||
WINS_GetSocketAddr,
|
WINS_GetSocketAddr,
|
||||||
WINS_GetNameFromAddr,
|
WINIPv4_GetNameFromAddr,
|
||||||
WINS_GetAddrFromName,
|
WINIPv4_GetAddrFromName,
|
||||||
WINS_AddrCompare,
|
WINS_AddrCompare,
|
||||||
WINS_GetSocketPort,
|
WINS_GetSocketPort,
|
||||||
WINS_SetSocketPort
|
WINS_SetSocketPort
|
||||||
},
|
},
|
||||||
|
#ifdef IPPROTO_IPV6
|
||||||
|
{ "Winsock IPv6",
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
WINIPv6_Init,
|
||||||
|
WINIPv6_Shutdown,
|
||||||
|
WINIPv6_Listen,
|
||||||
|
WINIPv6_OpenSocket,
|
||||||
|
WINS_CloseSocket,
|
||||||
|
WINS_Connect,
|
||||||
|
WINIPv6_CheckNewConnections,
|
||||||
|
WINS_Read,
|
||||||
|
WINS_Write,
|
||||||
|
WINIPv6_Broadcast,
|
||||||
|
WINS_AddrToString,
|
||||||
|
WINIPv6_StringToAddr,
|
||||||
|
WINS_GetSocketAddr,
|
||||||
|
WINIPv6_GetNameFromAddr,
|
||||||
|
WINIPv6_GetAddrFromName,
|
||||||
|
WINS_AddrCompare,
|
||||||
|
WINS_GetSocketPort,
|
||||||
|
WINS_SetSocketPort
|
||||||
|
},
|
||||||
|
#endif
|
||||||
{ "Winsock IPX",
|
{ "Winsock IPX",
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
|
|
639
Quake/net_wins.c
639
Quake/net_wins.c
|
@ -24,12 +24,30 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
#include "net_defs.h"
|
#include "net_defs.h"
|
||||||
|
|
||||||
static sys_socket_t net_acceptsocket = INVALID_SOCKET; // socket for fielding new connections
|
//ipv4 defs
|
||||||
static sys_socket_t net_controlsocket;
|
static sys_socket_t netv4_acceptsocket = INVALID_SOCKET; // socket for fielding new connections
|
||||||
static sys_socket_t net_broadcastsocket = 0;
|
static sys_socket_t netv4_controlsocket;
|
||||||
static struct sockaddr_in broadcastaddr;
|
static sys_socket_t netv4_broadcastsocket = INVALID_SOCKET;
|
||||||
|
static struct sockaddr_in broadcastaddrv4;
|
||||||
|
static in_addr_t myAddrv4, bindAddrv4; //spike --keeping separate bind and detected values.
|
||||||
|
|
||||||
|
//ipv6 defs
|
||||||
|
#ifdef IPPROTO_IPV6
|
||||||
|
typedef struct in_addr6 in_addr6_t;
|
||||||
|
static sys_socket_t netv6_acceptsocket = INVALID_SOCKET; // socket for fielding new connections
|
||||||
|
static sys_socket_t netv6_controlsocket;
|
||||||
|
static struct sockaddr_in6 broadcastaddrv6;
|
||||||
|
static in_addr6_t myAddrv6, bindAddrv6;
|
||||||
|
#ifndef IPV6_V6ONLY
|
||||||
|
#define IPV6_V6ONLY 27
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//getaddrinfo was added with winxp, but earlier versions don't do ipv6.
|
||||||
|
//we don't use hybrid sockets, so things are a little easier when it comes to xp vs vista.
|
||||||
|
//we don't detect the win2k ipv6 tech preview thing. it has different sized addresses, so lets hope microsoft's code handles that if it ever comes up.
|
||||||
|
int (WSAAPI *qgetaddrinfo)(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
|
||||||
|
|
||||||
static in_addr_t myAddr;
|
|
||||||
|
|
||||||
#include "net_wins.h"
|
#include "net_wins.h"
|
||||||
|
|
||||||
|
@ -70,20 +88,20 @@ static INT_PTR PASCAL FAR BlockingHook (void)
|
||||||
#endif /* ! _USE_WINSOCK2 */
|
#endif /* ! _USE_WINSOCK2 */
|
||||||
|
|
||||||
|
|
||||||
static void WINS_GetLocalAddress (void)
|
static void WINIPv4_GetLocalAddress (void)
|
||||||
{
|
{
|
||||||
struct hostent *local = NULL;
|
struct hostent *local = NULL;
|
||||||
char buff[MAXHOSTNAMELEN];
|
char buff[MAXHOSTNAMELEN];
|
||||||
in_addr_t addr;
|
in_addr_t addr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (myAddr != INADDR_ANY)
|
if (myAddrv4 != INADDR_ANY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
|
if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
err = SOCKETERRNO;
|
err = SOCKETERRNO;
|
||||||
Con_SafePrintf("WINS_GetLocalAddress: gethostname failed (%s)\n",
|
Con_SafePrintf("WINIPV4_GetLocalAddress: gethostname failed (%s)\n",
|
||||||
socketerror(err));
|
socketerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -100,24 +118,24 @@ static void WINS_GetLocalAddress (void)
|
||||||
#endif
|
#endif
|
||||||
if (local == NULL)
|
if (local == NULL)
|
||||||
{
|
{
|
||||||
Con_SafePrintf("WINS_GetLocalAddress: gethostbyname failed (%s)\n",
|
Con_SafePrintf("WINIPV4_GetLocalAddress: gethostbyname failed (%s)\n",
|
||||||
__WSAE_StrError(err));
|
__WSAE_StrError(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
myAddr = *(in_addr_t *)local->h_addr_list[0];
|
myAddrv4 = *(in_addr_t *)local->h_addr_list[0];
|
||||||
|
|
||||||
addr = ntohl(myAddr);
|
addr = ntohl(myAddrv4);
|
||||||
sprintf(my_tcpip_address, "%ld.%ld.%ld.%ld", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
|
sprintf(my_ipv4_address, "%ld.%ld.%ld.%ld", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sys_socket_t WINS_Init (void)
|
sys_socket_t WINIPv4_Init (void)
|
||||||
{
|
{
|
||||||
int i, err;
|
int i, err;
|
||||||
char buff[MAXHOSTNAMELEN];
|
char buff[MAXHOSTNAMELEN];
|
||||||
|
|
||||||
if (COM_CheckParm ("-noudp"))
|
if (COM_CheckParm ("-noudp") || COM_CheckParm ("-noudp4"))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (winsock_initialized == 0)
|
if (winsock_initialized == 0)
|
||||||
|
@ -148,10 +166,10 @@ sys_socket_t WINS_Init (void)
|
||||||
{
|
{
|
||||||
if (i < com_argc-1)
|
if (i < com_argc-1)
|
||||||
{
|
{
|
||||||
myAddr = inet_addr(com_argv[i+1]);
|
bindAddrv4 = inet_addr(com_argv[i+1]);
|
||||||
if (myAddr == INADDR_NONE)
|
if (bindAddrv4 == INADDR_NONE)
|
||||||
Sys_Error ("%s is not a valid IP address", com_argv[i+1]);
|
Sys_Error ("%s is not a valid IP address", com_argv[i+1]);
|
||||||
strcpy(my_tcpip_address, com_argv[i+1]);
|
strcpy(my_ipv4_address, com_argv[i+1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -160,11 +178,13 @@ sys_socket_t WINS_Init (void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
myAddr = INADDR_ANY;
|
bindAddrv4 = INADDR_ANY;
|
||||||
strcpy(my_tcpip_address, "INADDR_ANY");
|
strcpy(my_ipv4_address, "INADDR_ANY");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((net_controlsocket = WINS_OpenSocket(0)) == INVALID_SOCKET)
|
myAddrv4 = bindAddrv4;
|
||||||
|
|
||||||
|
if ((netv4_controlsocket = WINIPv4_OpenSocket(0)) == INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
Con_SafePrintf("WINS_Init: Unable to open control socket, UDP disabled\n");
|
Con_SafePrintf("WINS_Init: Unable to open control socket, UDP disabled\n");
|
||||||
if (--winsock_initialized == 0)
|
if (--winsock_initialized == 0)
|
||||||
|
@ -172,51 +192,51 @@ sys_socket_t WINS_Init (void)
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcastaddr.sin_family = AF_INET;
|
broadcastaddrv4.sin_family = AF_INET;
|
||||||
broadcastaddr.sin_addr.s_addr = INADDR_BROADCAST;
|
broadcastaddrv4.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
broadcastaddr.sin_port = htons((unsigned short)net_hostport);
|
broadcastaddrv4.sin_port = htons((unsigned short)net_hostport);
|
||||||
|
|
||||||
Con_SafePrintf("UDP Initialized\n");
|
Con_SafePrintf("IPv4 UDP Initialized\n");
|
||||||
tcpipAvailable = true;
|
ipv4Available = true;
|
||||||
|
|
||||||
return net_controlsocket;
|
return netv4_controlsocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void WINS_Shutdown (void)
|
void WINIPv4_Shutdown (void)
|
||||||
{
|
{
|
||||||
WINS_Listen (false);
|
WINIPv4_Listen (false);
|
||||||
WINS_CloseSocket (net_controlsocket);
|
WINS_CloseSocket (netv4_controlsocket);
|
||||||
if (--winsock_initialized == 0)
|
if (--winsock_initialized == 0)
|
||||||
WSACleanup ();
|
WSACleanup ();
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void WINS_Listen (qboolean state)
|
sys_socket_t WINIPv4_Listen (qboolean state)
|
||||||
{
|
{
|
||||||
// enable listening
|
// enable listening
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
if (net_acceptsocket != INVALID_SOCKET)
|
if (netv4_acceptsocket != INVALID_SOCKET)
|
||||||
return;
|
return netv4_acceptsocket;
|
||||||
WINS_GetLocalAddress();
|
WINIPv4_GetLocalAddress();
|
||||||
if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == INVALID_SOCKET)
|
netv4_acceptsocket = WINIPv4_OpenSocket (net_hostport);
|
||||||
Sys_Error ("WINS_Listen: Unable to open accept socket");
|
return netv4_acceptsocket;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable listening
|
// disable listening
|
||||||
if (net_acceptsocket == INVALID_SOCKET)
|
if (netv4_acceptsocket == INVALID_SOCKET)
|
||||||
return;
|
return INVALID_SOCKET;
|
||||||
WINS_CloseSocket (net_acceptsocket);
|
WINS_CloseSocket (netv4_acceptsocket);
|
||||||
net_acceptsocket = INVALID_SOCKET;
|
netv4_acceptsocket = INVALID_SOCKET;
|
||||||
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
sys_socket_t WINS_OpenSocket (int port)
|
sys_socket_t WINIPv4_OpenSocket (int port)
|
||||||
{
|
{
|
||||||
sys_socket_t newsocket;
|
sys_socket_t newsocket;
|
||||||
struct sockaddr_in address;
|
struct sockaddr_in address;
|
||||||
|
@ -235,16 +255,16 @@ sys_socket_t WINS_OpenSocket (int port)
|
||||||
|
|
||||||
memset(&address, 0, sizeof(struct sockaddr_in));
|
memset(&address, 0, sizeof(struct sockaddr_in));
|
||||||
address.sin_family = AF_INET;
|
address.sin_family = AF_INET;
|
||||||
address.sin_addr.s_addr = myAddr;
|
address.sin_addr.s_addr = bindAddrv4;
|
||||||
address.sin_port = htons((unsigned short)port);
|
address.sin_port = htons((unsigned short)port);
|
||||||
if (bind (newsocket, (struct sockaddr *)&address, sizeof(address)) == 0)
|
if (bind (newsocket, (struct sockaddr *)&address, sizeof(address)) == 0)
|
||||||
return newsocket;
|
return newsocket;
|
||||||
|
|
||||||
if (tcpipAvailable)
|
if (ipv4Available)
|
||||||
{
|
{
|
||||||
err = SOCKETERRNO;
|
err = SOCKETERRNO;
|
||||||
Sys_Error ("Unable to bind to %s (%s)",
|
Con_Warning ("Unable to bind to %s (%s)\n",
|
||||||
WINS_AddrToString ((struct qsockaddr *) &address),
|
WINS_AddrToString ((struct qsockaddr *) &address, false),
|
||||||
socketerror(err));
|
socketerror(err));
|
||||||
return INVALID_SOCKET; /* not reached */
|
return INVALID_SOCKET; /* not reached */
|
||||||
}
|
}
|
||||||
|
@ -261,8 +281,8 @@ ErrorReturn:
|
||||||
|
|
||||||
int WINS_CloseSocket (sys_socket_t socketid)
|
int WINS_CloseSocket (sys_socket_t socketid)
|
||||||
{
|
{
|
||||||
if (socketid == net_broadcastsocket)
|
if (socketid == netv4_broadcastsocket)
|
||||||
net_broadcastsocket = 0;
|
netv4_broadcastsocket = INVALID_SOCKET;
|
||||||
return closesocket (socketid);
|
return closesocket (socketid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +337,7 @@ static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr)
|
||||||
hostaddr->qsa_family = AF_INET;
|
hostaddr->qsa_family = AF_INET;
|
||||||
((struct sockaddr_in *)hostaddr)->sin_port = htons((unsigned short)port);
|
((struct sockaddr_in *)hostaddr)->sin_port = htons((unsigned short)port);
|
||||||
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr =
|
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr =
|
||||||
(myAddr & htonl(mask)) | htonl(addr);
|
(myAddrv4 & htonl(mask)) | htonl(addr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -331,17 +351,17 @@ int WINS_Connect (sys_socket_t socketid, struct qsockaddr *addr)
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
sys_socket_t WINS_CheckNewConnections (void)
|
sys_socket_t WINIPv4_CheckNewConnections (void)
|
||||||
{
|
{
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
|
||||||
if (net_acceptsocket == INVALID_SOCKET)
|
if (netv4_acceptsocket == INVALID_SOCKET)
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
|
|
||||||
if (recvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL)
|
if (recvfrom (netv4_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL)
|
||||||
!= SOCKET_ERROR)
|
!= SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
return net_acceptsocket;
|
return netv4_acceptsocket;
|
||||||
}
|
}
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
@ -359,7 +379,10 @@ int WINS_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr
|
||||||
int err = SOCKETERRNO;
|
int err = SOCKETERRNO;
|
||||||
if (err == NET_EWOULDBLOCK || err == NET_ECONNREFUSED)
|
if (err == NET_EWOULDBLOCK || err == NET_ECONNREFUSED)
|
||||||
return 0;
|
return 0;
|
||||||
Con_SafePrintf ("WINS_Read, recvfrom: %s\n", socketerror(err));
|
if (err == WSAECONNRESET)
|
||||||
|
Con_DPrintf ("WINS_Read, recvfrom: %s (%s)\n", socketerror(err), WINS_AddrToString(addr, false));
|
||||||
|
else
|
||||||
|
Con_SafePrintf ("WINS_Read, recvfrom: %s\n", socketerror(err));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -378,31 +401,31 @@ static int WINS_MakeSocketBroadcastCapable (sys_socket_t socketid)
|
||||||
Con_SafePrintf ("UDP, setsockopt: %s\n", socketerror(err));
|
Con_SafePrintf ("UDP, setsockopt: %s\n", socketerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
net_broadcastsocket = socketid;
|
netv4_broadcastsocket = socketid;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int WINS_Broadcast (sys_socket_t socketid, byte *buf, int len)
|
int WINIPv4_Broadcast (sys_socket_t socketid, byte *buf, int len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (socketid != net_broadcastsocket)
|
if (socketid != netv4_broadcastsocket)
|
||||||
{
|
{
|
||||||
if (net_broadcastsocket != 0)
|
if (netv4_broadcastsocket != INVALID_SOCKET)
|
||||||
Sys_Error("Attempted to use multiple broadcasts sockets");
|
Sys_Error("Attempted to use multiple broadcasts sockets");
|
||||||
WINS_GetLocalAddress();
|
WINIPv4_GetLocalAddress();
|
||||||
ret = WINS_MakeSocketBroadcastCapable (socketid);
|
ret = WINS_MakeSocketBroadcastCapable (socketid);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
Con_Printf("Unable to make socket broadcast capable\n");
|
Con_SafePrintf("Unable to make socket broadcast capable\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return WINS_Write (socketid, buf, len, (struct qsockaddr *)&broadcastaddr);
|
return WINS_Write (socketid, buf, len, (struct qsockaddr *)&broadcastaddrv4);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -425,21 +448,81 @@ int WINS_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *add
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
const char *WINS_AddrToString (struct qsockaddr *addr)
|
unsigned short ntohs_v6word(struct qsockaddr *addr, int wordnum)
|
||||||
{
|
{
|
||||||
static char buffer[22];
|
unsigned char *ptr = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr + wordnum*2;
|
||||||
|
return (unsigned short)(ptr[0]<<8) | ptr[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *WINS_AddrToString (struct qsockaddr *addr, qboolean masked)
|
||||||
|
{
|
||||||
|
static char buffer[64];
|
||||||
int haddr;
|
int haddr;
|
||||||
|
|
||||||
haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
#ifdef IPPROTO_IPV6
|
||||||
sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff,
|
if (addr->qsa_family == AF_INET6)
|
||||||
(haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff,
|
{
|
||||||
ntohs(((struct sockaddr_in *)addr)->sin_port));
|
if (masked)
|
||||||
|
{
|
||||||
|
q_snprintf(buffer, sizeof(buffer), "[%x:%x:%x:%x::]/64",
|
||||||
|
ntohs_v6word(addr, 0),
|
||||||
|
ntohs_v6word(addr, 1),
|
||||||
|
ntohs_v6word(addr, 2),
|
||||||
|
ntohs_v6word(addr, 3));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (((struct sockaddr_in6 *)addr)->sin6_scope_id)
|
||||||
|
{
|
||||||
|
q_snprintf(buffer, sizeof(buffer), "[%x:%x:%x:%x:%x:%x:%x:%x%%%i]:%d",
|
||||||
|
ntohs_v6word(addr, 0),
|
||||||
|
ntohs_v6word(addr, 1),
|
||||||
|
ntohs_v6word(addr, 2),
|
||||||
|
ntohs_v6word(addr, 3),
|
||||||
|
ntohs_v6word(addr, 4),
|
||||||
|
ntohs_v6word(addr, 5),
|
||||||
|
ntohs_v6word(addr, 6),
|
||||||
|
ntohs_v6word(addr, 7),
|
||||||
|
(int)((struct sockaddr_in6 *)addr)->sin6_scope_id,
|
||||||
|
ntohs(((struct sockaddr_in6 *)addr)->sin6_port));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
q_snprintf(buffer, sizeof(buffer), "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
|
||||||
|
ntohs_v6word(addr, 0),
|
||||||
|
ntohs_v6word(addr, 1),
|
||||||
|
ntohs_v6word(addr, 2),
|
||||||
|
ntohs_v6word(addr, 3),
|
||||||
|
ntohs_v6word(addr, 4),
|
||||||
|
ntohs_v6word(addr, 5),
|
||||||
|
ntohs_v6word(addr, 6),
|
||||||
|
ntohs_v6word(addr, 7),
|
||||||
|
ntohs(((struct sockaddr_in6 *)addr)->sin6_port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
||||||
|
if (masked)
|
||||||
|
{
|
||||||
|
sprintf(buffer, "%d.%d.%d.0/24", (haddr >> 24) & 0xff,
|
||||||
|
(haddr >> 16) & 0xff, (haddr >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff,
|
||||||
|
(haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff,
|
||||||
|
ntohs(((struct sockaddr_in *)addr)->sin_port));
|
||||||
|
}
|
||||||
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int WINS_StringToAddr (const char *string, struct qsockaddr *addr)
|
int WINIPv4_StringToAddr (const char *string, struct qsockaddr *addr)
|
||||||
{
|
{
|
||||||
int ha1, ha2, ha3, ha4, hp, ipaddr;
|
int ha1, ha2, ha3, ha4, hp, ipaddr;
|
||||||
|
|
||||||
|
@ -457,21 +540,31 @@ int WINS_StringToAddr (const char *string, struct qsockaddr *addr)
|
||||||
int WINS_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr)
|
int WINS_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr)
|
||||||
{
|
{
|
||||||
socklen_t addrlen = sizeof(struct qsockaddr);
|
socklen_t addrlen = sizeof(struct qsockaddr);
|
||||||
in_addr_t a;
|
|
||||||
|
|
||||||
memset(addr, 0, sizeof(struct qsockaddr));
|
memset(addr, 0, sizeof(struct qsockaddr));
|
||||||
getsockname(socketid, (struct sockaddr *)addr, &addrlen);
|
getsockname(socketid, (struct sockaddr *)addr, &addrlen);
|
||||||
|
|
||||||
a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
if (addr->qsa_family == AF_INET)
|
||||||
if (a == 0 || a == htonl(INADDR_LOOPBACK))
|
{
|
||||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
|
in_addr_t a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
||||||
|
if (a == 0 || a == htonl(INADDR_LOOPBACK))
|
||||||
|
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddrv4;
|
||||||
|
}
|
||||||
|
#ifdef IPPROTO_IPV6
|
||||||
|
if (addr->qsa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
static const in_addr6_t in6addr_any;// = IN6ADDR_ANY_INIT;
|
||||||
|
if (!memcmp(&((struct sockaddr_in6 *)addr)->sin6_addr, &in6addr_any, sizeof(in_addr6_t)))
|
||||||
|
memcpy(&((struct sockaddr_in6 *)addr)->sin6_addr, &myAddrv6, sizeof(struct sockaddr_in6));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
int WINIPv4_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
||||||
{
|
{
|
||||||
struct hostent *hostentry;
|
struct hostent *hostentry;
|
||||||
|
|
||||||
|
@ -483,25 +576,41 @@ int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_strcpy (name, WINS_AddrToString (addr));
|
Q_strcpy (name, WINS_AddrToString (addr, false));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
int WINS_GetAddrFromName (const char *name, struct qsockaddr *addr)
|
int WINIPv4_GetAddrFromName (const char *name, struct qsockaddr *addr)
|
||||||
{
|
{
|
||||||
struct hostent *hostentry;
|
struct hostent *hostentry;
|
||||||
|
char *colon;
|
||||||
|
unsigned short port = net_hostport;
|
||||||
|
|
||||||
if (name[0] >= '0' && name[0] <= '9')
|
if (name[0] >= '0' && name[0] <= '9')
|
||||||
return PartialIPAddress (name, addr);
|
return PartialIPAddress (name, addr);
|
||||||
|
|
||||||
hostentry = gethostbyname (name);
|
colon = strrchr(name, ':');
|
||||||
|
if (colon)
|
||||||
|
{
|
||||||
|
char dupe[MAXHOSTNAMELEN];
|
||||||
|
if (colon-name+1 > MAXHOSTNAMELEN)
|
||||||
|
return -1;
|
||||||
|
memcpy(dupe, name, colon-name);
|
||||||
|
dupe[colon-name] = 0;
|
||||||
|
if (strchr(dupe, ':'))
|
||||||
|
return -1; //don't resolve a name to an ipv4 address if it has multiple colons in it. its probably an ipx or ipv6 address, and I'd rather not block on any screwed dns resolves
|
||||||
|
hostentry = gethostbyname (dupe);
|
||||||
|
port = strtoul(colon+1, NULL, 10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hostentry = gethostbyname (name);
|
||||||
if (!hostentry)
|
if (!hostentry)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
addr->qsa_family = AF_INET;
|
addr->qsa_family = AF_INET;
|
||||||
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);
|
((struct sockaddr_in *)addr)->sin_port = htons(port);
|
||||||
((struct sockaddr_in *)addr)->sin_addr.s_addr =
|
((struct sockaddr_in *)addr)->sin_addr.s_addr =
|
||||||
*(in_addr_t *)hostentry->h_addr_list[0];
|
*(in_addr_t *)hostentry->h_addr_list[0];
|
||||||
|
|
||||||
|
@ -515,13 +624,32 @@ int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||||
if (addr1->qsa_family != addr2->qsa_family)
|
if (addr1->qsa_family != addr2->qsa_family)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (((struct sockaddr_in *)addr1)->sin_addr.s_addr !=
|
#ifdef IPPROTO_IPV6
|
||||||
((struct sockaddr_in *)addr2)->sin_addr.s_addr)
|
if (addr1->qsa_family == AF_INET6)
|
||||||
return -1;
|
{
|
||||||
|
if (memcmp(&((struct sockaddr_in6 *)addr1)->sin6_addr, &((struct sockaddr_in6 *)addr2)->sin6_addr, sizeof(((struct sockaddr_in6 *)addr2)->sin6_addr)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (((struct sockaddr_in *)addr1)->sin_port !=
|
if (((struct sockaddr_in6 *)addr1)->sin6_port !=
|
||||||
((struct sockaddr_in *)addr2)->sin_port)
|
((struct sockaddr_in6 *)addr2)->sin6_port)
|
||||||
return 1;
|
return 1;
|
||||||
|
if (((struct sockaddr_in6 *)addr1)->sin6_scope_id &&
|
||||||
|
((struct sockaddr_in6 *)addr2)->sin6_scope_id &&
|
||||||
|
((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
|
||||||
|
((struct sockaddr_in6 *)addr2)->sin6_scope_id) //the ipv6 scope id is for use with link-local addresses, to identify the specific interface.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (((struct sockaddr_in *)addr1)->sin_addr.s_addr !=
|
||||||
|
((struct sockaddr_in *)addr2)->sin_addr.s_addr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (((struct sockaddr_in *)addr1)->sin_port !=
|
||||||
|
((struct sockaddr_in *)addr2)->sin_port)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -530,15 +658,358 @@ int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||||
|
|
||||||
int WINS_GetSocketPort (struct qsockaddr *addr)
|
int WINS_GetSocketPort (struct qsockaddr *addr)
|
||||||
{
|
{
|
||||||
return ntohs(((struct sockaddr_in *)addr)->sin_port);
|
#ifdef IPPROTO_IPV6
|
||||||
|
if (addr->qsa_family == AF_INET6)
|
||||||
|
return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
return ntohs(((struct sockaddr_in *)addr)->sin_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int WINS_SetSocketPort (struct qsockaddr *addr, int port)
|
int WINS_SetSocketPort (struct qsockaddr *addr, int port)
|
||||||
{
|
{
|
||||||
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
|
#ifdef IPPROTO_IPV6
|
||||||
|
if (addr->qsa_family == AF_INET6)
|
||||||
|
((struct sockaddr_in6 *)addr)->sin6_port = htons((unsigned short)port);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IPPROTO_IPV6
|
||||||
|
//winxp (and possibly win2k) is dual stack.
|
||||||
|
//vista+ has a hybrid stack
|
||||||
|
|
||||||
|
static void WINIPv6_GetLocalAddress (void)
|
||||||
|
{
|
||||||
|
char buff[MAXHOSTNAMELEN];
|
||||||
|
int err;
|
||||||
|
struct addrinfo hints, *local = NULL;
|
||||||
|
|
||||||
|
// if (myAddrv6 != IN6ADDR_ANY)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
err = SOCKETERRNO;
|
||||||
|
Con_SafePrintf("WINIPv6_GetLocalAddress: gethostname failed (%s)\n",
|
||||||
|
socketerror(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buff[MAXHOSTNAMELEN - 1] = 0;
|
||||||
|
|
||||||
|
#ifndef _USE_WINSOCK2
|
||||||
|
blocktime = Sys_DoubleTime();
|
||||||
|
WSASetBlockingHook(BlockingHook);
|
||||||
|
#endif
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET6;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
|
if (qgetaddrinfo && qgetaddrinfo(buff, NULL, &hints, &local) == 0)
|
||||||
|
{
|
||||||
|
size_t l;
|
||||||
|
q_strlcpy(my_ipv6_address, WINS_AddrToString((struct qsockaddr*)local->ai_addr, false), sizeof(my_ipv6_address));
|
||||||
|
l = strlen(my_ipv6_address);
|
||||||
|
if (l > 2 && !strcmp(my_ipv6_address+l-2, ":0"))
|
||||||
|
my_ipv6_address[l-2] = 0;
|
||||||
|
freeaddrinfo(local);
|
||||||
|
}
|
||||||
|
err = WSAGetLastError();
|
||||||
|
#ifndef _USE_WINSOCK2
|
||||||
|
WSAUnhookBlockingHook();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (local == NULL)
|
||||||
|
{
|
||||||
|
Con_SafePrintf("WINIPv6_GetLocalAddress: gethostbyname failed (%s)\n",
|
||||||
|
__WSAE_StrError(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_socket_t WINIPv6_Init (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char buff[MAXHOSTNAMELEN];
|
||||||
|
|
||||||
|
if (COM_CheckParm ("-noudp") || COM_CheckParm ("-noudp6"))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
qgetaddrinfo = (void*)GetProcAddress(GetModuleHandle("ws2_32.dll"), "getaddrinfo");
|
||||||
|
if (!qgetaddrinfo)
|
||||||
|
{
|
||||||
|
Con_SafePrintf("Winsock lacks getaddrinfo, ipv6 support is unavailable.\n");
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (winsock_initialized == 0)
|
||||||
|
{
|
||||||
|
int err = WSAStartup(MAKEWORD(2,2), &winsockdata);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
Con_SafePrintf("Winsock initialization failed (%s)\n",
|
||||||
|
socketerror(err));
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
winsock_initialized++;
|
||||||
|
|
||||||
|
// determine my name & address
|
||||||
|
if (gethostname(buff, MAXHOSTNAMELEN) != 0)
|
||||||
|
{
|
||||||
|
int err = SOCKETERRNO;
|
||||||
|
Con_SafePrintf("WINIPv6_Init: gethostname failed (%s)\n",
|
||||||
|
socketerror(err));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buff[MAXHOSTNAMELEN - 1] = 0;
|
||||||
|
}
|
||||||
|
i = COM_CheckParm ("-ip6");
|
||||||
|
if (i)
|
||||||
|
{
|
||||||
|
if (i < com_argc-1)
|
||||||
|
{
|
||||||
|
if (WINIPv6_GetAddrFromName(com_argv[i+1], (struct qsockaddr*)&bindAddrv6))
|
||||||
|
Sys_Error ("%s is not a valid IPv6 address", com_argv[i+1]);
|
||||||
|
if (!*my_ipv6_address)
|
||||||
|
strcpy(my_ipv6_address, com_argv[i+1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Sys_Error ("WINIPv6_Init: you must specify an IP address after -ip");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(&bindAddrv6, 0, sizeof(bindAddrv6));
|
||||||
|
if (!*my_ipv6_address)
|
||||||
|
{
|
||||||
|
strcpy(my_ipv6_address, "[::]");
|
||||||
|
WINIPv6_GetLocalAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
myAddrv6 = bindAddrv6;
|
||||||
|
|
||||||
|
if ((netv6_controlsocket = WINIPv6_OpenSocket(0)) == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
Con_SafePrintf("WINIPv6_Init: Unable to open control socket, UDP disabled\n");
|
||||||
|
if (--winsock_initialized == 0)
|
||||||
|
WSACleanup ();
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
broadcastaddrv6.sin6_family = AF_INET6;
|
||||||
|
memset(&broadcastaddrv6.sin6_addr, 0, sizeof(broadcastaddrv6.sin6_addr));
|
||||||
|
broadcastaddrv6.sin6_addr.s6_addr[0] = 0xff;
|
||||||
|
broadcastaddrv6.sin6_addr.s6_addr[1] = 0x03;
|
||||||
|
broadcastaddrv6.sin6_addr.s6_addr[15] = 0x01;
|
||||||
|
broadcastaddrv6.sin6_port = htons((unsigned short)net_hostport);
|
||||||
|
|
||||||
|
Con_SafePrintf("IPv6 UDP Initialized\n");
|
||||||
|
ipv6Available = true;
|
||||||
|
|
||||||
|
return netv6_controlsocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_socket_t WINIPv6_Listen (qboolean state)
|
||||||
|
{
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
// enable listening
|
||||||
|
if (netv6_acceptsocket == INVALID_SOCKET)
|
||||||
|
netv6_acceptsocket = WINIPv6_OpenSocket (net_hostport);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// disable listening
|
||||||
|
if (netv6_acceptsocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
WINS_CloseSocket (netv6_acceptsocket);
|
||||||
|
netv6_acceptsocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return netv6_acceptsocket;
|
||||||
|
}
|
||||||
|
void WINIPv6_Shutdown (void)
|
||||||
|
{
|
||||||
|
WINIPv6_Listen(false);
|
||||||
|
WINS_CloseSocket (netv6_controlsocket);
|
||||||
|
if (--winsock_initialized == 0)
|
||||||
|
WSACleanup ();
|
||||||
|
}
|
||||||
|
sys_socket_t WINIPv6_OpenSocket (int port)
|
||||||
|
{
|
||||||
|
sys_socket_t newsocket;
|
||||||
|
struct sockaddr_in6 address;
|
||||||
|
u_long _true = 1;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if ((newsocket = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
err = SOCKETERRNO;
|
||||||
|
Con_SafePrintf("WINS_OpenSocket: %s\n", socketerror(err));
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&_true, sizeof(_true));
|
||||||
|
|
||||||
|
if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR)
|
||||||
|
goto ErrorReturn;
|
||||||
|
|
||||||
|
memset(&address, 0, sizeof(address));
|
||||||
|
address.sin6_family = AF_INET6;
|
||||||
|
address.sin6_addr = bindAddrv6;
|
||||||
|
address.sin6_port = htons((unsigned short)port);
|
||||||
|
if (bind (newsocket, (struct sockaddr *)&address, sizeof(address)) == 0)
|
||||||
|
{
|
||||||
|
//we don't know if we're the server or not. oh well.
|
||||||
|
struct ipv6_mreq req;
|
||||||
|
req.ipv6mr_multiaddr = broadcastaddrv6.sin6_addr;
|
||||||
|
req.ipv6mr_interface = 0;
|
||||||
|
setsockopt(newsocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&req, sizeof(req));
|
||||||
|
|
||||||
|
|
||||||
|
return newsocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipv6Available)
|
||||||
|
{
|
||||||
|
err = SOCKETERRNO;
|
||||||
|
Con_Warning ("Unable to bind to %s (%s)\n",
|
||||||
|
WINS_AddrToString ((struct qsockaddr *) &address, false),
|
||||||
|
socketerror(err));
|
||||||
|
return INVALID_SOCKET; /* not reached */
|
||||||
|
}
|
||||||
|
/* else: we are still in init phase, no need to error */
|
||||||
|
|
||||||
|
ErrorReturn:
|
||||||
|
err = SOCKETERRNO;
|
||||||
|
Con_SafePrintf("WINS_OpenSocket: %s\n", socketerror(err));
|
||||||
|
closesocket (newsocket);
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
sys_socket_t WINIPv6_CheckNewConnections (void)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
if (netv6_acceptsocket == INVALID_SOCKET)
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
|
||||||
|
if (recvfrom (netv6_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL)
|
||||||
|
!= SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
return netv6_acceptsocket;
|
||||||
|
}
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
int WINIPv6_Broadcast (sys_socket_t socketid, byte *buf, int len)
|
||||||
|
{
|
||||||
|
broadcastaddrv6.sin6_port = htons((unsigned short)net_hostport);
|
||||||
|
return WINS_Write(socketid, buf, len, (struct qsockaddr*)&broadcastaddrv6);
|
||||||
|
}
|
||||||
|
int WINIPv6_StringToAddr (const char *string, struct qsockaddr *addr)
|
||||||
|
{ //This is never actually called...
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int WINIPv6_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
||||||
|
{
|
||||||
|
//FIXME: should really do a reverse dns lookup.
|
||||||
|
q_strlcpy(name, WINS_AddrToString(addr, false), NET_NAMELEN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int WINIPv6_GetAddrFromName (const char *name, struct qsockaddr *addr)
|
||||||
|
{
|
||||||
|
//ipv6 addresses take form of [::1]:26000 or eg localhost:26000. just ::1 is NOT supported, but localhost as-is is okay. [localhost]:26000 is acceptable, but will fail to resolve as ipv4.
|
||||||
|
struct addrinfo *addrinfo = NULL;
|
||||||
|
struct addrinfo *pos;
|
||||||
|
struct addrinfo udp6hint;
|
||||||
|
int error;
|
||||||
|
char *port;
|
||||||
|
char dupbase[256];
|
||||||
|
size_t len;
|
||||||
|
qboolean success = false;
|
||||||
|
|
||||||
|
memset(&udp6hint, 0, sizeof(udp6hint));
|
||||||
|
udp6hint.ai_family = 0;//Any... we check for AF_INET6 or 4
|
||||||
|
udp6hint.ai_socktype = SOCK_DGRAM;
|
||||||
|
udp6hint.ai_protocol = IPPROTO_UDP;
|
||||||
|
|
||||||
|
if (*name == '[')
|
||||||
|
{
|
||||||
|
port = strstr(name, "]");
|
||||||
|
if (!port)
|
||||||
|
error = EAI_NONAME;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len = port - (name+1);
|
||||||
|
if (len >= sizeof(dupbase))
|
||||||
|
len = sizeof(dupbase)-1;
|
||||||
|
strncpy(dupbase, name+1, len);
|
||||||
|
dupbase[len] = '\0';
|
||||||
|
error = qgetaddrinfo?qgetaddrinfo(dupbase, (port[1] == ':')?port+2:NULL, &udp6hint, &addrinfo):EAI_NONAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port = strrchr(name, ':');
|
||||||
|
|
||||||
|
if (port)
|
||||||
|
{
|
||||||
|
len = port - name;
|
||||||
|
if (len >= sizeof(dupbase))
|
||||||
|
len = sizeof(dupbase)-1;
|
||||||
|
strncpy(dupbase, name, len);
|
||||||
|
dupbase[len] = '\0';
|
||||||
|
error = qgetaddrinfo?qgetaddrinfo(dupbase, port+1, &udp6hint, &addrinfo):EAI_NONAME;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = EAI_NONAME;
|
||||||
|
if (error) //failed, try string with no port.
|
||||||
|
error = qgetaddrinfo?qgetaddrinfo(name, NULL, &udp6hint, &addrinfo):EAI_NONAME; //remember, this func will return any address family that could be using the udp protocol... (ip4 or ip6)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
((struct sockaddr*)addr)->sa_family = 0;
|
||||||
|
for (pos = addrinfo; pos; pos = pos->ai_next)
|
||||||
|
{
|
||||||
|
if (0)//pos->ai_family == AF_INET)
|
||||||
|
{
|
||||||
|
memcpy(addr, pos->ai_addr, pos->ai_addrlen);
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pos->ai_family == AF_INET6 && !success)
|
||||||
|
{
|
||||||
|
memcpy(addr, pos->ai_addr, pos->ai_addrlen);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeaddrinfo (addrinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
if (((struct sockaddr*)addr)->sa_family == AF_INET)
|
||||||
|
{
|
||||||
|
if (!((struct sockaddr_in *)addr)->sin_port)
|
||||||
|
((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);
|
||||||
|
}
|
||||||
|
else if (((struct sockaddr*)addr)->sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
if (!((struct sockaddr_in6 *)addr)->sin6_port)
|
||||||
|
((struct sockaddr_in6 *)addr)->sin6_port = htons(net_hostport);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -22,24 +22,38 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#ifndef __NET_WINSOCK_H
|
#ifndef __NET_WINSOCK_H
|
||||||
#define __NET_WINSOCK_H
|
#define __NET_WINSOCK_H
|
||||||
|
|
||||||
sys_socket_t WINS_Init (void);
|
|
||||||
void WINS_Shutdown (void);
|
|
||||||
void WINS_Listen (qboolean state);
|
|
||||||
sys_socket_t WINS_OpenSocket (int port);
|
|
||||||
int WINS_CloseSocket (sys_socket_t socketid);
|
int WINS_CloseSocket (sys_socket_t socketid);
|
||||||
int WINS_Connect (sys_socket_t socketid, struct qsockaddr *addr);
|
int WINS_Connect (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
sys_socket_t WINS_CheckNewConnections (void);
|
|
||||||
int WINS_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
int WINS_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
int WINS_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
int WINS_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
int WINS_Broadcast (sys_socket_t socketid, byte *buf, int len);
|
const char *WINS_AddrToString (struct qsockaddr *addr, qboolean masked);
|
||||||
const char *WINS_AddrToString (struct qsockaddr *addr);
|
|
||||||
int WINS_StringToAddr (const char *string, struct qsockaddr *addr);
|
|
||||||
int WINS_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr);
|
int WINS_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
|
||||||
int WINS_GetAddrFromName (const char *name, struct qsockaddr *addr);
|
|
||||||
int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||||
int WINS_GetSocketPort (struct qsockaddr *addr);
|
int WINS_GetSocketPort (struct qsockaddr *addr);
|
||||||
int WINS_SetSocketPort (struct qsockaddr *addr, int port);
|
int WINS_SetSocketPort (struct qsockaddr *addr, int port);
|
||||||
|
|
||||||
|
sys_socket_t WINIPv4_Init (void);
|
||||||
|
void WINIPv4_Shutdown (void);
|
||||||
|
sys_socket_t WINIPv4_Listen (qboolean state);
|
||||||
|
sys_socket_t WINIPv4_OpenSocket (int port);
|
||||||
|
sys_socket_t WINIPv4_CheckNewConnections (void);
|
||||||
|
int WINIPv4_Broadcast (sys_socket_t socketid, byte *buf, int len);
|
||||||
|
int WINIPv4_StringToAddr (const char *string, struct qsockaddr *addr);
|
||||||
|
int WINIPv4_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
||||||
|
int WINIPv4_GetAddrFromName (const char *name, struct qsockaddr *addr);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IPPROTO_IPV6
|
||||||
|
sys_socket_t WINIPv6_Init (void);
|
||||||
|
void WINIPv6_Shutdown (void);
|
||||||
|
sys_socket_t WINIPv6_Listen (qboolean state);
|
||||||
|
sys_socket_t WINIPv6_OpenSocket (int port);
|
||||||
|
sys_socket_t WINIPv6_CheckNewConnections (void);
|
||||||
|
int WINIPv6_Broadcast (sys_socket_t socketid, byte *buf, int len);
|
||||||
|
int WINIPv6_StringToAddr (const char *string, struct qsockaddr *addr);
|
||||||
|
int WINIPv6_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
||||||
|
int WINIPv6_GetAddrFromName (const char *name, struct qsockaddr *addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __NET_WINSOCK_H */
|
#endif /* __NET_WINSOCK_H */
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ sys_socket_t WIPX_Init (void)
|
||||||
broadcastaddr.sa_socket = htons((unsigned short)net_hostport);
|
broadcastaddr.sa_socket = htons((unsigned short)net_hostport);
|
||||||
|
|
||||||
WIPX_GetSocketAddr (net_controlsocket, &addr);
|
WIPX_GetSocketAddr (net_controlsocket, &addr);
|
||||||
Q_strcpy(my_ipx_address, WIPX_AddrToString (&addr));
|
Q_strcpy(my_ipx_address, WIPX_AddrToString (&addr, false));
|
||||||
colon = Q_strrchr (my_ipx_address, ':');
|
colon = Q_strrchr (my_ipx_address, ':');
|
||||||
if (colon)
|
if (colon)
|
||||||
*colon = 0;
|
*colon = 0;
|
||||||
|
@ -120,23 +120,27 @@ void WIPX_Shutdown (void)
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
void WIPX_Listen (qboolean state)
|
sys_socket_t WIPX_Listen (qboolean state)
|
||||||
{
|
{
|
||||||
// enable listening
|
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
if (net_acceptsocket != INVALID_SOCKET)
|
// enable listening
|
||||||
return;
|
if (net_acceptsocket == INVALID_SOCKET)
|
||||||
if ((net_acceptsocket = WIPX_OpenSocket (net_hostport)) == INVALID_SOCKET)
|
{
|
||||||
Sys_Error ("WIPX_Listen: Unable to open accept socket");
|
if ((net_acceptsocket = WIPX_OpenSocket (net_hostport)) == INVALID_SOCKET)
|
||||||
return;
|
Sys_Error ("WIPX_Listen: Unable to open accept socket");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// disable listening
|
{
|
||||||
if (net_acceptsocket == INVALID_SOCKET)
|
// disable listening
|
||||||
return;
|
if (net_acceptsocket != INVALID_SOCKET)
|
||||||
WIPX_CloseSocket (net_acceptsocket);
|
{
|
||||||
net_acceptsocket = INVALID_SOCKET;
|
WIPX_CloseSocket (net_acceptsocket);
|
||||||
|
net_acceptsocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return net_acceptsocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -300,23 +304,36 @@ int WIPX_Write (sys_socket_t handle, byte *buf, int len, struct qsockaddr *addr)
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
const char *WIPX_AddrToString (struct qsockaddr *addr)
|
const char *WIPX_AddrToString (struct qsockaddr *addr, qboolean masked)
|
||||||
{
|
{
|
||||||
static char buf[28];
|
static char buf[28];
|
||||||
|
|
||||||
sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
|
if (masked)
|
||||||
((struct sockaddr_ipx *)addr)->sa_netnum[0] & 0xff,
|
{
|
||||||
((struct sockaddr_ipx *)addr)->sa_netnum[1] & 0xff,
|
sprintf(buf, "%02x%02x%02x%02x:??""??""??""??""??""??:%u",
|
||||||
((struct sockaddr_ipx *)addr)->sa_netnum[2] & 0xff,
|
((struct sockaddr_ipx *)addr)->sa_netnum[0] & 0xff,
|
||||||
((struct sockaddr_ipx *)addr)->sa_netnum[3] & 0xff,
|
((struct sockaddr_ipx *)addr)->sa_netnum[1] & 0xff,
|
||||||
((struct sockaddr_ipx *)addr)->sa_nodenum[0] & 0xff,
|
((struct sockaddr_ipx *)addr)->sa_netnum[2] & 0xff,
|
||||||
((struct sockaddr_ipx *)addr)->sa_nodenum[1] & 0xff,
|
((struct sockaddr_ipx *)addr)->sa_netnum[3] & 0xff,
|
||||||
((struct sockaddr_ipx *)addr)->sa_nodenum[2] & 0xff,
|
ntohs(((struct sockaddr_ipx *)addr)->sa_socket)
|
||||||
((struct sockaddr_ipx *)addr)->sa_nodenum[3] & 0xff,
|
);
|
||||||
((struct sockaddr_ipx *)addr)->sa_nodenum[4] & 0xff,
|
}
|
||||||
((struct sockaddr_ipx *)addr)->sa_nodenum[5] & 0xff,
|
else
|
||||||
ntohs(((struct sockaddr_ipx *)addr)->sa_socket)
|
{
|
||||||
);
|
sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_netnum[0] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_netnum[1] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_netnum[2] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_netnum[3] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_nodenum[0] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_nodenum[1] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_nodenum[2] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_nodenum[3] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_nodenum[4] & 0xff,
|
||||||
|
((struct sockaddr_ipx *)addr)->sa_nodenum[5] & 0xff,
|
||||||
|
ntohs(((struct sockaddr_ipx *)addr)->sa_socket)
|
||||||
|
);
|
||||||
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +396,7 @@ int WIPX_GetSocketAddr (sys_socket_t handle, struct qsockaddr *addr)
|
||||||
|
|
||||||
int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
||||||
{
|
{
|
||||||
Q_strcpy(name, WIPX_AddrToString(addr));
|
Q_strcpy(name, WIPX_AddrToString(addr, false));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
sys_socket_t WIPX_Init (void);
|
sys_socket_t WIPX_Init (void);
|
||||||
void WIPX_Shutdown (void);
|
void WIPX_Shutdown (void);
|
||||||
void WIPX_Listen (qboolean state);
|
sys_socket_t WIPX_Listen (qboolean state);
|
||||||
sys_socket_t WIPX_OpenSocket (int port);
|
sys_socket_t WIPX_OpenSocket (int port);
|
||||||
int WIPX_CloseSocket (sys_socket_t socketid);
|
int WIPX_CloseSocket (sys_socket_t socketid);
|
||||||
int WIPX_Connect (sys_socket_t socketid, struct qsockaddr *addr);
|
int WIPX_Connect (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
|
@ -32,7 +32,7 @@ sys_socket_t WIPX_CheckNewConnections (void);
|
||||||
int WIPX_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
int WIPX_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
int WIPX_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
int WIPX_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr);
|
||||||
int WIPX_Broadcast (sys_socket_t socketid, byte *buf, int len);
|
int WIPX_Broadcast (sys_socket_t socketid, byte *buf, int len);
|
||||||
const char *WIPX_AddrToString (struct qsockaddr *addr);
|
const char *WIPX_AddrToString (struct qsockaddr *addr, qboolean masked);
|
||||||
int WIPX_StringToAddr (const char *string, struct qsockaddr *addr);
|
int WIPX_StringToAddr (const char *string, struct qsockaddr *addr);
|
||||||
int WIPX_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr);
|
int WIPX_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr);
|
||||||
int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name);
|
||||||
|
|
276
Quake/pr_cmds.c
276
Quake/pr_cmds.c
|
@ -27,17 +27,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
|
static char pr_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
|
||||||
static byte pr_string_tempindex = 0;
|
static byte pr_string_tempindex = 0;
|
||||||
|
|
||||||
static char *PR_GetTempString (void)
|
char *PR_GetTempString (void)
|
||||||
{
|
{
|
||||||
return pr_string_temp[(STRINGTEMP_BUFFERS-1) & ++pr_string_tempindex];
|
return pr_string_temp[(STRINGTEMP_BUFFERS-1) & ++pr_string_tempindex];
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
|
#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
|
||||||
|
|
||||||
#define MSG_BROADCAST 0 // unreliable to all
|
#define MSG_BROADCAST 0 // unreliable to all
|
||||||
#define MSG_ONE 1 // reliable to one (msg_entity)
|
#define MSG_ONE 1 // reliable to one (msg_entity)
|
||||||
#define MSG_ALL 2 // reliable to all
|
#define MSG_ALL 2 // reliable to all
|
||||||
#define MSG_INIT 3 // write to the init string
|
#define MSG_INIT 3 // write to the init string
|
||||||
|
#define MSG_EXT_MULTICAST 4 // temporary buffer that can be splurged more reliably / with more control.
|
||||||
|
#define MSG_EXT_ENTITY 5 // for csqc networking. we don't actually support this. I'm just defining it for completeness.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============================================================================
|
===============================================================================
|
||||||
|
@ -47,7 +49,7 @@ static char *PR_GetTempString (void)
|
||||||
===============================================================================
|
===============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char *PF_VarString (int first)
|
char *PF_VarString (int first)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
static char out[1024];
|
static char out[1024];
|
||||||
|
@ -287,7 +289,20 @@ static void PF_setmodel (void)
|
||||||
|
|
||||||
if (!*check)
|
if (!*check)
|
||||||
{
|
{
|
||||||
PR_RunError ("no precache: %s", m);
|
if (pr_checkextension.value)
|
||||||
|
{ //Spike: so that func_illusionaries work with custom models even in vanilla.
|
||||||
|
if (sv.state == ss_loading)
|
||||||
|
Con_DWarning("PF_setmodel(\"%s\"): Model was not precached\n", m);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// PR_PrintStatement(pr_statements + pr_xstatement);
|
||||||
|
// PR_StackTrace();
|
||||||
|
Con_Warning("PF_setmodel(\"%s\"): Model was not precached\n", m);
|
||||||
|
}
|
||||||
|
i = SV_Precache_Model(m);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PR_RunError ("no precache: %s", m);
|
||||||
}
|
}
|
||||||
e->v.model = PR_SetEngineString(*check);
|
e->v.model = PR_SetEngineString(*check);
|
||||||
e->v.modelindex = i; //SV_ModelIndex (m);
|
e->v.modelindex = i; //SV_ModelIndex (m);
|
||||||
|
@ -511,13 +526,15 @@ PF_Random
|
||||||
Returns a number from 0 <= num < 1
|
Returns a number from 0 <= num < 1
|
||||||
|
|
||||||
random()
|
random()
|
||||||
|
|
||||||
|
bug: vanilla could return 1, contrary to the (unchanged) comment just above.
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static void PF_random (void)
|
static void PF_random (void)
|
||||||
{
|
{
|
||||||
float num;
|
float num;
|
||||||
|
|
||||||
num = (rand() & 0x7fff) / ((float)0x7fff);
|
num = (rand() & 0x7fff) / ((float)0x8000);
|
||||||
|
|
||||||
G_FLOAT(OFS_RETURN) = num;
|
G_FLOAT(OFS_RETURN) = num;
|
||||||
}
|
}
|
||||||
|
@ -554,8 +571,8 @@ static void PF_ambientsound (void)
|
||||||
const char *samp, **check;
|
const char *samp, **check;
|
||||||
float *pos;
|
float *pos;
|
||||||
float vol, attenuation;
|
float vol, attenuation;
|
||||||
int i, soundnum;
|
int soundnum;
|
||||||
int large = false; //johnfitz -- PROTOCOL_FITZQUAKE
|
struct ambientsound_s *st;
|
||||||
|
|
||||||
pos = G_VECTOR (OFS_PARM0);
|
pos = G_VECTOR (OFS_PARM0);
|
||||||
samp = G_STRING(OFS_PARM1);
|
samp = G_STRING(OFS_PARM1);
|
||||||
|
@ -575,38 +592,22 @@ static void PF_ambientsound (void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//johnfitz -- PROTOCOL_FITZQUAKE
|
//generate data to splurge on a per-client basis in SV_SendAmbientSounds
|
||||||
if (soundnum > 255)
|
if (sv.num_ambients == sv.max_ambients)
|
||||||
{
|
{
|
||||||
if (sv.protocol == PROTOCOL_NETQUAKE)
|
int nm = sv.max_ambients + 128;
|
||||||
return; //don't send any info protocol can't support
|
struct ambientsound_s *n = (nm*sizeof(*n)<sv.max_ambients*sizeof(*n))?NULL:realloc(sv.ambientsounds, nm*sizeof(*n));
|
||||||
else
|
if (!n)
|
||||||
large = true;
|
PR_RunError ("PF_ambientsound: out of memory"); //shouldn't really happen.
|
||||||
|
sv.ambientsounds = n;
|
||||||
|
memset(sv.ambientsounds+sv.max_ambients, 0, (nm-sv.max_ambients)*sizeof(*n));
|
||||||
|
sv.max_ambients = nm;
|
||||||
}
|
}
|
||||||
//johnfitz
|
st = &sv.ambientsounds[sv.num_ambients++];
|
||||||
|
VectorCopy(pos, st->origin);
|
||||||
// add an svc_spawnambient command to the level signon packet
|
st->soundindex = soundnum;
|
||||||
|
st->volume = vol;
|
||||||
//johnfitz -- PROTOCOL_FITZQUAKE
|
st->attenuation = attenuation;
|
||||||
if (large)
|
|
||||||
MSG_WriteByte (&sv.signon,svc_spawnstaticsound2);
|
|
||||||
else
|
|
||||||
MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
|
|
||||||
//johnfitz
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
MSG_WriteCoord(&sv.signon, pos[i], sv.protocolflags);
|
|
||||||
|
|
||||||
//johnfitz -- PROTOCOL_FITZQUAKE
|
|
||||||
if (large)
|
|
||||||
MSG_WriteShort(&sv.signon, soundnum);
|
|
||||||
else
|
|
||||||
MSG_WriteByte (&sv.signon, soundnum);
|
|
||||||
//johnfitz
|
|
||||||
|
|
||||||
MSG_WriteByte (&sv.signon, vol*255);
|
|
||||||
MSG_WriteByte (&sv.signon, attenuation*64);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -638,6 +639,7 @@ static void PF_sound (void)
|
||||||
volume = G_FLOAT(OFS_PARM3) * 255;
|
volume = G_FLOAT(OFS_PARM3) * 255;
|
||||||
attenuation = G_FLOAT(OFS_PARM4);
|
attenuation = G_FLOAT(OFS_PARM4);
|
||||||
|
|
||||||
|
/* Spike -- these checks are redundant
|
||||||
if (volume < 0 || volume > 255)
|
if (volume < 0 || volume > 255)
|
||||||
Host_Error ("SV_StartSound: volume = %i", volume);
|
Host_Error ("SV_StartSound: volume = %i", volume);
|
||||||
|
|
||||||
|
@ -646,8 +648,8 @@ static void PF_sound (void)
|
||||||
|
|
||||||
if (channel < 0 || channel > 7)
|
if (channel < 0 || channel > 7)
|
||||||
Host_Error ("SV_StartSound: channel = %i", channel);
|
Host_Error ("SV_StartSound: channel = %i", channel);
|
||||||
|
*/
|
||||||
SV_StartSound (entity, channel, sample, volume, attenuation);
|
SV_StartSound (entity, NULL, channel, sample, volume, attenuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1075,29 +1077,70 @@ static void PF_precache_file (void)
|
||||||
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PF_precache_sound (void)
|
int SV_Precache_Sound(const char *s)
|
||||||
{
|
{ //must be a persistent string.
|
||||||
const char *s;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (sv.state != ss_loading)
|
|
||||||
PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
|
|
||||||
|
|
||||||
s = G_STRING(OFS_PARM0);
|
|
||||||
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
|
||||||
PR_CheckEmptyString (s);
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_SOUNDS; i++)
|
for (i = 0; i < MAX_SOUNDS; i++)
|
||||||
{
|
{
|
||||||
if (!sv.sound_precache[i])
|
if (!sv.sound_precache[i])
|
||||||
{
|
{
|
||||||
|
if (sv.state != ss_loading) //spike -- moved this so that there's no actual error any more.
|
||||||
|
{
|
||||||
|
Con_Warning("PF_precache_sound(\"%s\"): Precache should only be done in spawn functions\n", s);
|
||||||
|
//let existing clients know about it
|
||||||
|
MSG_WriteByte(&sv.reliable_datagram, svcdp_precache);
|
||||||
|
MSG_WriteShort(&sv.reliable_datagram, i|0x8000);
|
||||||
|
MSG_WriteString(&sv.reliable_datagram, s);
|
||||||
|
}
|
||||||
sv.sound_precache[i] = s;
|
sv.sound_precache[i] = s;
|
||||||
return;
|
return i;
|
||||||
}
|
}
|
||||||
if (!strcmp(sv.sound_precache[i], s))
|
if (!strcmp(sv.sound_precache[i], s))
|
||||||
return;
|
{
|
||||||
|
if (sv.state != ss_loading && !pr_checkextension.value)
|
||||||
|
Con_Warning("PF_precache_sound(\"%s\"): Precache should only be done in spawn functions\n", s);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PR_RunError ("PF_precache_sound: overflow");
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PF_precache_sound (void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
s = G_STRING(OFS_PARM0);
|
||||||
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
||||||
|
PR_CheckEmptyString (s);
|
||||||
|
|
||||||
|
if (!SV_Precache_Sound(s))
|
||||||
|
PR_RunError ("PF_precache_sound: overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
int SV_Precache_Model(const char *s)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < MAX_MODELS; i++)
|
||||||
|
{
|
||||||
|
if (!sv.model_precache[i])
|
||||||
|
{
|
||||||
|
if (sv.state != ss_loading)
|
||||||
|
{
|
||||||
|
//let existing clients know about it
|
||||||
|
MSG_WriteByte(&sv.reliable_datagram, svcdp_precache);
|
||||||
|
MSG_WriteShort(&sv.reliable_datagram, i|0x8000);
|
||||||
|
MSG_WriteString(&sv.reliable_datagram, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
sv.model_precache[i] = s;
|
||||||
|
sv.models[i] = Mod_ForName (s, i==1);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
if (!strcmp(sv.model_precache[i], s))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PF_precache_model (void)
|
static void PF_precache_model (void)
|
||||||
|
@ -1105,9 +1148,6 @@ static void PF_precache_model (void)
|
||||||
const char *s;
|
const char *s;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (sv.state != ss_loading)
|
|
||||||
PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
|
|
||||||
|
|
||||||
s = G_STRING(OFS_PARM0);
|
s = G_STRING(OFS_PARM0);
|
||||||
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
||||||
PR_CheckEmptyString (s);
|
PR_CheckEmptyString (s);
|
||||||
|
@ -1116,12 +1156,25 @@ static void PF_precache_model (void)
|
||||||
{
|
{
|
||||||
if (!sv.model_precache[i])
|
if (!sv.model_precache[i])
|
||||||
{
|
{
|
||||||
|
if (sv.state != ss_loading)
|
||||||
|
{
|
||||||
|
Con_Warning ("PF_precache_model(\"%s\"): Precache should only be done in spawn functions\n", s);
|
||||||
|
//let existing clients know about it
|
||||||
|
MSG_WriteByte(&sv.reliable_datagram, svcdp_precache);
|
||||||
|
MSG_WriteShort(&sv.reliable_datagram, i|0x8000);
|
||||||
|
MSG_WriteString(&sv.reliable_datagram, s);
|
||||||
|
}
|
||||||
|
|
||||||
sv.model_precache[i] = s;
|
sv.model_precache[i] = s;
|
||||||
sv.models[i] = Mod_ForName (s, true);
|
sv.models[i] = Mod_ForName (s, i==1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!strcmp(sv.model_precache[i], s))
|
if (!strcmp(sv.model_precache[i], s))
|
||||||
|
{
|
||||||
|
if (sv.state != ss_loading && !pr_checkextension.value)
|
||||||
|
Con_Warning ("PF_precache_model(\"%s\"): Precache should only be done in spawn functions\n", s);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PR_RunError ("PF_precache_model: overflow");
|
PR_RunError ("PF_precache_model: overflow");
|
||||||
}
|
}
|
||||||
|
@ -1475,7 +1528,7 @@ MESSAGE WRITING
|
||||||
===============================================================================
|
===============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static sizebuf_t *WriteDest (void)
|
sizebuf_t *WriteDest (void)
|
||||||
{
|
{
|
||||||
int entnum;
|
int entnum;
|
||||||
int dest;
|
int dest;
|
||||||
|
@ -1500,6 +1553,9 @@ static sizebuf_t *WriteDest (void)
|
||||||
case MSG_INIT:
|
case MSG_INIT:
|
||||||
return &sv.signon;
|
return &sv.signon;
|
||||||
|
|
||||||
|
case MSG_EXT_MULTICAST:
|
||||||
|
return &sv.multicast;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PR_RunError ("WriteDest: bad destination");
|
PR_RunError ("WriteDest: bad destination");
|
||||||
break;
|
break;
|
||||||
|
@ -1543,78 +1599,37 @@ static void PF_WriteString (void)
|
||||||
MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
|
MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MSG_WriteEntity MSG_WriteShort //fixme - replacement deltas encodes 0x8000+ in 24 bits
|
||||||
static void PF_WriteEntity (void)
|
static void PF_WriteEntity (void)
|
||||||
{
|
{
|
||||||
MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
|
MSG_WriteEntity (WriteDest(), G_EDICTNUM(OFS_PARM1));
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
static void PF_makestatic (void)
|
static void PF_makestatic (void)
|
||||||
{
|
{
|
||||||
|
entity_state_t *st;
|
||||||
edict_t *ent;
|
edict_t *ent;
|
||||||
int i;
|
|
||||||
int bits = 0; //johnfitz -- PROTOCOL_FITZQUAKE
|
|
||||||
|
|
||||||
ent = G_EDICT(OFS_PARM0);
|
ent = G_EDICT(OFS_PARM0);
|
||||||
|
|
||||||
//johnfitz -- don't send invisible static entities
|
if (sv.num_statics == sv.max_statics)
|
||||||
if (ent->alpha == ENTALPHA_ZERO) {
|
|
||||||
ED_Free (ent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//johnfitz
|
|
||||||
|
|
||||||
//johnfitz -- PROTOCOL_FITZQUAKE
|
|
||||||
if (sv.protocol == PROTOCOL_NETQUAKE)
|
|
||||||
{
|
{
|
||||||
if (SV_ModelIndex(PR_GetString(ent->v.model)) & 0xFF00 || (int)(ent->v.frame) & 0xFF00)
|
int nm = sv.max_statics + 128;
|
||||||
{
|
entity_state_t *n = (nm*sizeof(*n)<sv.max_statics*sizeof(*n))?NULL:realloc(sv.static_entities, nm*sizeof(*n));
|
||||||
ED_Free (ent);
|
if (!n)
|
||||||
return; //can't display the correct model & frame, so don't show it at all
|
PR_RunError ("PF_makestatic: out of memory"); //shouldn't really happen.
|
||||||
}
|
sv.static_entities = n;
|
||||||
|
memset(sv.static_entities+sv.max_statics, 0, (nm-sv.max_statics)*sizeof(*n));
|
||||||
|
sv.max_statics = nm;
|
||||||
}
|
}
|
||||||
|
st = &sv.static_entities[sv.num_statics];
|
||||||
|
SV_BuildEntityState(ent, st);
|
||||||
|
if (st->alpha == ENTALPHA_ZERO)
|
||||||
|
; //no point
|
||||||
else
|
else
|
||||||
{
|
sv.num_statics++;
|
||||||
if (SV_ModelIndex(PR_GetString(ent->v.model)) & 0xFF00)
|
|
||||||
bits |= B_LARGEMODEL;
|
|
||||||
if ((int)(ent->v.frame) & 0xFF00)
|
|
||||||
bits |= B_LARGEFRAME;
|
|
||||||
if (ent->alpha != ENTALPHA_DEFAULT)
|
|
||||||
bits |= B_ALPHA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bits)
|
|
||||||
{
|
|
||||||
MSG_WriteByte (&sv.signon, svc_spawnstatic2);
|
|
||||||
MSG_WriteByte (&sv.signon, bits);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
MSG_WriteByte (&sv.signon, svc_spawnstatic);
|
|
||||||
|
|
||||||
if (bits & B_LARGEMODEL)
|
|
||||||
MSG_WriteShort (&sv.signon, SV_ModelIndex(PR_GetString(ent->v.model)));
|
|
||||||
else
|
|
||||||
MSG_WriteByte (&sv.signon, SV_ModelIndex(PR_GetString(ent->v.model)));
|
|
||||||
|
|
||||||
if (bits & B_LARGEFRAME)
|
|
||||||
MSG_WriteShort (&sv.signon, ent->v.frame);
|
|
||||||
else
|
|
||||||
MSG_WriteByte (&sv.signon, ent->v.frame);
|
|
||||||
//johnfitz
|
|
||||||
|
|
||||||
MSG_WriteByte (&sv.signon, ent->v.colormap);
|
|
||||||
MSG_WriteByte (&sv.signon, ent->v.skin);
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
MSG_WriteCoord(&sv.signon, ent->v.origin[i], sv.protocolflags);
|
|
||||||
MSG_WriteAngle(&sv.signon, ent->v.angles[i], sv.protocolflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
//johnfitz -- PROTOCOL_FITZQUAKE
|
|
||||||
if (bits & B_ALPHA)
|
|
||||||
MSG_WriteByte (&sv.signon, ent->alpha);
|
|
||||||
//johnfitz
|
|
||||||
|
|
||||||
// throw the entity away now
|
// throw the entity away now
|
||||||
ED_Free (ent);
|
ED_Free (ent);
|
||||||
|
@ -1663,11 +1678,30 @@ static void PF_changelevel (void)
|
||||||
Cbuf_AddText (va("changelevel %s\n",s));
|
Cbuf_AddText (va("changelevel %s\n",s));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PF_Fixme (void)
|
void PF_Fixme (void);
|
||||||
{
|
//{
|
||||||
PR_RunError ("unimplemented builtin");
|
// PR_RunError ("unimplemented builtin");
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
void PR_spawnfunc_misc_model(edict_t *self)
|
||||||
|
{
|
||||||
|
eval_t *val;
|
||||||
|
if (!self->v.model && (val = GetEdictFieldValue(self, ED_FindFieldOffset("mdl"))))
|
||||||
|
self->v.model = val->string;
|
||||||
|
if (!*PR_GetString(self->v.model)) //must have a model, because otherwise various things will assume its not valid at all.
|
||||||
|
self->v.model = PR_SetEngineString("*null");
|
||||||
|
|
||||||
|
if (self->v.angles[1] < 0) //mimic AD. shame there's no avelocity clientside.
|
||||||
|
self->v.angles[1] = (rand()*(360.0f/RAND_MAX));
|
||||||
|
|
||||||
|
//make sure the model is precached, to avoid errors.
|
||||||
|
G_INT(OFS_PARM0) = self->v.model;
|
||||||
|
PF_precache_model();
|
||||||
|
|
||||||
|
//and lets just call makestatic instead of worrying if it'll interfere with the rest of the qc.
|
||||||
|
G_INT(OFS_PARM0) = EDICT_TO_PROG(self);
|
||||||
|
PF_makestatic();
|
||||||
|
}
|
||||||
|
|
||||||
static builtin_t pr_builtin[] =
|
static builtin_t pr_builtin[] =
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,7 +37,9 @@ typedef enum
|
||||||
ev_entity,
|
ev_entity,
|
||||||
ev_field,
|
ev_field,
|
||||||
ev_function,
|
ev_function,
|
||||||
ev_pointer
|
ev_pointer,
|
||||||
|
|
||||||
|
ev_ext_integer
|
||||||
} etype_t;
|
} etype_t;
|
||||||
|
|
||||||
#define OFS_NULL 0
|
#define OFS_NULL 0
|
||||||
|
|
227
Quake/pr_edict.c
227
Quake/pr_edict.c
|
@ -23,6 +23,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
|
|
||||||
|
struct pr_extfields_s pr_extfields;
|
||||||
|
|
||||||
dprograms_t *progs;
|
dprograms_t *progs;
|
||||||
dfunction_t *pr_functions;
|
dfunction_t *pr_functions;
|
||||||
|
|
||||||
|
@ -31,11 +33,10 @@ static int pr_stringssize;
|
||||||
static const char **pr_knownstrings;
|
static const char **pr_knownstrings;
|
||||||
static int pr_maxknownstrings;
|
static int pr_maxknownstrings;
|
||||||
static int pr_numknownstrings;
|
static int pr_numknownstrings;
|
||||||
static ddef_t *pr_fielddefs;
|
static int pr_freeknownstrings;
|
||||||
|
ddef_t *pr_fielddefs;
|
||||||
static ddef_t *pr_globaldefs;
|
static ddef_t *pr_globaldefs;
|
||||||
|
|
||||||
qboolean pr_alpha_supported; //johnfitz
|
|
||||||
|
|
||||||
dstatement_t *pr_statements;
|
dstatement_t *pr_statements;
|
||||||
globalvars_t *pr_global_struct;
|
globalvars_t *pr_global_struct;
|
||||||
float *pr_globals; // same as pr_global_struct
|
float *pr_globals; // same as pr_global_struct
|
||||||
|
@ -55,21 +56,7 @@ int type_size[8] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static ddef_t *ED_FieldAtOfs (int ofs);
|
static ddef_t *ED_FieldAtOfs (int ofs);
|
||||||
static qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s);
|
qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s);
|
||||||
|
|
||||||
#define MAX_FIELD_LEN 64
|
|
||||||
#define GEFV_CACHESIZE 2
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
ddef_t *pcache;
|
|
||||||
char field[MAX_FIELD_LEN];
|
|
||||||
} gefv_cache;
|
|
||||||
|
|
||||||
static gefv_cache gefvCache[GEFV_CACHESIZE] =
|
|
||||||
{
|
|
||||||
{ NULL, "" },
|
|
||||||
{ NULL, "" }
|
|
||||||
};
|
|
||||||
|
|
||||||
cvar_t nomonsters = {"nomonsters", "0", CVAR_NONE};
|
cvar_t nomonsters = {"nomonsters", "0", CVAR_NONE};
|
||||||
cvar_t gamecfg = {"gamecfg", "0", CVAR_NONE};
|
cvar_t gamecfg = {"gamecfg", "0", CVAR_NONE};
|
||||||
|
@ -207,7 +194,7 @@ static ddef_t *ED_FieldAtOfs (int ofs)
|
||||||
ED_FindField
|
ED_FindField
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
static ddef_t *ED_FindField (const char *name)
|
ddef_t *ED_FindField (const char *name)
|
||||||
{
|
{
|
||||||
ddef_t *def;
|
ddef_t *def;
|
||||||
int i;
|
int i;
|
||||||
|
@ -221,13 +208,22 @@ static ddef_t *ED_FindField (const char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
int ED_FindFieldOffset (const char *name)
|
||||||
|
{
|
||||||
|
ddef_t *def = ED_FindField(name);
|
||||||
|
if (!def)
|
||||||
|
return -1;
|
||||||
|
return def->ofs;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
ED_FindGlobal
|
ED_FindGlobal
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
static ddef_t *ED_FindGlobal (const char *name)
|
ddef_t *ED_FindGlobal (const char *name)
|
||||||
{
|
{
|
||||||
ddef_t *def;
|
ddef_t *def;
|
||||||
int i;
|
int i;
|
||||||
|
@ -247,7 +243,7 @@ static ddef_t *ED_FindGlobal (const char *name)
|
||||||
ED_FindFunction
|
ED_FindFunction
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
static dfunction_t *ED_FindFunction (const char *fn_name)
|
dfunction_t *ED_FindFunction (const char *fn_name)
|
||||||
{
|
{
|
||||||
dfunction_t *func;
|
dfunction_t *func;
|
||||||
int i;
|
int i;
|
||||||
|
@ -266,35 +262,12 @@ static dfunction_t *ED_FindFunction (const char *fn_name)
|
||||||
GetEdictFieldValue
|
GetEdictFieldValue
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
eval_t *GetEdictFieldValue(edict_t *ed, const char *field)
|
eval_t *GetEdictFieldValue(edict_t *ed, int fldofs)
|
||||||
{
|
{
|
||||||
ddef_t *def = NULL;
|
if (fldofs < 0)
|
||||||
int i;
|
|
||||||
static int rep = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < GEFV_CACHESIZE; i++)
|
|
||||||
{
|
|
||||||
if (!strcmp(field, gefvCache[i].field))
|
|
||||||
{
|
|
||||||
def = gefvCache[i].pcache;
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def = ED_FindField (field);
|
|
||||||
|
|
||||||
if (strlen(field) < MAX_FIELD_LEN)
|
|
||||||
{
|
|
||||||
gefvCache[rep].pcache = def;
|
|
||||||
strcpy (gefvCache[rep].field, field);
|
|
||||||
rep ^= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Done:
|
|
||||||
if (!def)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return (eval_t *)((char *)&ed->v + def->ofs*4);
|
return (eval_t *)((char *)&ed->v + fldofs*4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -336,6 +309,9 @@ static const char *PR_ValueString (int type, eval_t *val)
|
||||||
case ev_float:
|
case ev_float:
|
||||||
sprintf (line, "%5.1f", val->_float);
|
sprintf (line, "%5.1f", val->_float);
|
||||||
break;
|
break;
|
||||||
|
case ev_ext_integer:
|
||||||
|
sprintf (line, "%i", val->_int);
|
||||||
|
break;
|
||||||
case ev_vector:
|
case ev_vector:
|
||||||
sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]);
|
sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]);
|
||||||
break;
|
break;
|
||||||
|
@ -359,7 +335,7 @@ Returns a string describing *data in a type specific manner
|
||||||
Easier to parse than PR_ValueString
|
Easier to parse than PR_ValueString
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static const char *PR_UglyValueString (int type, eval_t *val)
|
const char *PR_UglyValueString (int type, eval_t *val)
|
||||||
{
|
{
|
||||||
static char line[1024];
|
static char line[1024];
|
||||||
ddef_t *def;
|
ddef_t *def;
|
||||||
|
@ -389,6 +365,9 @@ static const char *PR_UglyValueString (int type, eval_t *val)
|
||||||
case ev_float:
|
case ev_float:
|
||||||
q_snprintf (line, sizeof(line), "%f", val->_float);
|
q_snprintf (line, sizeof(line), "%f", val->_float);
|
||||||
break;
|
break;
|
||||||
|
case ev_ext_integer:
|
||||||
|
sprintf (line, "%i", val->_int);
|
||||||
|
break;
|
||||||
case ev_vector:
|
case ev_vector:
|
||||||
q_snprintf (line, sizeof(line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
|
q_snprintf (line, sizeof(line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
|
||||||
break;
|
break;
|
||||||
|
@ -554,7 +533,7 @@ void ED_Write (FILE *f, edict_t *ed)
|
||||||
}
|
}
|
||||||
|
|
||||||
//johnfitz -- save entity alpha manually when progs.dat doesn't know about alpha
|
//johnfitz -- save entity alpha manually when progs.dat doesn't know about alpha
|
||||||
if (!pr_alpha_supported && ed->alpha != ENTALPHA_DEFAULT)
|
if (pr_extfields.alpha<0 && ed->alpha != ENTALPHA_DEFAULT)
|
||||||
fprintf (f, "\"alpha\" \"%f\"\n", ENTALPHA_TOSAVE(ed->alpha));
|
fprintf (f, "\"alpha\" \"%f\"\n", ENTALPHA_TOSAVE(ed->alpha));
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
|
||||||
|
@ -771,7 +750,7 @@ Can parse either fields or globals
|
||||||
returns false if error
|
returns false if error
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s)
|
qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char string[128];
|
char string[128];
|
||||||
|
@ -793,6 +772,10 @@ static qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s)
|
||||||
*(float *)d = atof (s);
|
*(float *)d = atof (s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ev_ext_integer:
|
||||||
|
*(int *)d = atoi (s);
|
||||||
|
break;
|
||||||
|
|
||||||
case ev_vector:
|
case ev_vector:
|
||||||
q_strlcpy (string, s, sizeof(string));
|
q_strlcpy (string, s, sizeof(string));
|
||||||
end = (char *)string + strlen(string);
|
end = (char *)string + strlen(string);
|
||||||
|
@ -919,18 +902,54 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
|
||||||
// keynames with a leading underscore are used for utility comments,
|
// keynames with a leading underscore are used for utility comments,
|
||||||
// and are immediately discarded by quake
|
// and are immediately discarded by quake
|
||||||
if (keyname[0] == '_')
|
if (keyname[0] == '_')
|
||||||
|
{
|
||||||
|
//spike -- hacks to support func_illusionary with all sorts of mdls, and various particle effects
|
||||||
|
if (!strcmp(keyname, "_precache_model") && sv.state == ss_loading)
|
||||||
|
SV_Precache_Model(PR_GetString(ED_NewString(com_token)));
|
||||||
|
else if (!strcmp(keyname, "_precache_sound") && sv.state == ss_loading)
|
||||||
|
SV_Precache_Sound(PR_GetString(ED_NewString(com_token)));
|
||||||
|
//spike
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//johnfitz -- hack to support .alpha even when progs.dat doesn't know about it
|
//johnfitz -- hack to support .alpha even when progs.dat doesn't know about it
|
||||||
if (!strcmp(keyname, "alpha"))
|
if (!strcmp(keyname, "alpha"))
|
||||||
ent->alpha = ENTALPHA_ENCODE(atof(com_token));
|
ent->alpha = ENTALPHA_ENCODE(atof(com_token));
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
|
||||||
|
//spike -- hacks to support func_illusionary/info_notnull with all sorts of mdls, and various particle effects
|
||||||
|
if (!strcmp(keyname, "modelindex") && sv.state == ss_loading)
|
||||||
|
{
|
||||||
|
//"model" "progs/foobar.mdl"
|
||||||
|
//"modelindex" "progs/foobar.mdl"
|
||||||
|
//"mins" "-16 -16 -16"
|
||||||
|
//"maxs" "16 16 16"
|
||||||
|
char *e;
|
||||||
|
strtol(com_token, &e, 0);
|
||||||
|
if (e != com_token && *e)
|
||||||
|
ent->v.modelindex = SV_Precache_Model(PR_GetString(ED_NewString(com_token)));
|
||||||
|
}
|
||||||
|
//spike
|
||||||
|
|
||||||
key = ED_FindField (keyname);
|
key = ED_FindField (keyname);
|
||||||
if (!key)
|
if (!key)
|
||||||
{
|
{
|
||||||
|
#ifdef PSET_SCRIPT
|
||||||
|
eval_t *val;
|
||||||
|
if (!strcmp(keyname, "traileffect") && sv.state == ss_loading)
|
||||||
|
{
|
||||||
|
if ((val = GetEdictFieldValue(ent, pr_extfields.traileffectnum)))
|
||||||
|
val->_float = PF_SV_ForceParticlePrecache(com_token);
|
||||||
|
}
|
||||||
|
else if (!strcmp(keyname, "emiteffect") && sv.state == ss_loading)
|
||||||
|
{
|
||||||
|
if ((val = GetEdictFieldValue(ent, pr_extfields.emiteffectnum)))
|
||||||
|
val->_float = PF_SV_ForceParticlePrecache(com_token);
|
||||||
|
}
|
||||||
//johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc
|
//johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc
|
||||||
if (strncmp(keyname, "sky", 3) && strcmp(keyname, "fog") && strcmp(keyname, "alpha"))
|
else
|
||||||
|
#endif
|
||||||
|
if (strncmp(keyname, "sky", 3) && strcmp(keyname, "fog") && strcmp(keyname, "alpha"))
|
||||||
Con_DPrintf ("\"%s\" is not a field\n", keyname); //johnfitz -- was Con_Printf
|
Con_DPrintf ("\"%s\" is not a field\n", keyname); //johnfitz -- was Con_Printf
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -973,6 +992,7 @@ void ED_LoadFromFile (const char *data)
|
||||||
dfunction_t *func;
|
dfunction_t *func;
|
||||||
edict_t *ent = NULL;
|
edict_t *ent = NULL;
|
||||||
int inhibit = 0;
|
int inhibit = 0;
|
||||||
|
int usingspawnfunc = 0;
|
||||||
|
|
||||||
pr_global_struct->time = sv.time;
|
pr_global_struct->time = sv.time;
|
||||||
|
|
||||||
|
@ -1023,13 +1043,27 @@ void ED_LoadFromFile (const char *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// look for the spawn function
|
// look for the spawn function
|
||||||
func = ED_FindFunction ( PR_GetString(ent->v.classname) );
|
//
|
||||||
|
func = ED_FindFunction (va("spawnfunc_%s", PR_GetString(ent->v.classname)));
|
||||||
|
if (func)
|
||||||
|
{
|
||||||
|
if (!usingspawnfunc++)
|
||||||
|
Con_DPrintf2 ("Using DP_SV_SPAWNFUNC_PREFIX\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
func = ED_FindFunction ( PR_GetString(ent->v.classname) );
|
||||||
|
|
||||||
if (!func)
|
if (!func)
|
||||||
{
|
{
|
||||||
Con_SafePrintf ("No spawn function for:\n"); //johnfitz -- was Con_Printf
|
const char *classname = PR_GetString(ent->v.classname);
|
||||||
ED_Print (ent);
|
if (!strcmp(classname, "misc_model"))
|
||||||
ED_Free (ent);
|
PR_spawnfunc_misc_model(ent);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_SafePrintf ("No spawn function for:\n"); //johnfitz -- was Con_Printf
|
||||||
|
ED_Print (ent);
|
||||||
|
ED_Free (ent);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1049,10 +1083,9 @@ PR_LoadProgs
|
||||||
void PR_LoadProgs (void)
|
void PR_LoadProgs (void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
unsigned int u;
|
||||||
|
|
||||||
// flush the non-C variable lookup cache
|
PR_ShutdownExtensions();
|
||||||
for (i = 0; i < GEFV_CACHESIZE; i++)
|
|
||||||
gefvCache[i].field[0] = 0;
|
|
||||||
|
|
||||||
CRC_Init (&pr_crc);
|
CRC_Init (&pr_crc);
|
||||||
|
|
||||||
|
@ -1080,6 +1113,7 @@ void PR_LoadProgs (void)
|
||||||
|
|
||||||
// initialize the strings
|
// initialize the strings
|
||||||
pr_numknownstrings = 0;
|
pr_numknownstrings = 0;
|
||||||
|
pr_freeknownstrings = 0;
|
||||||
pr_maxknownstrings = 0;
|
pr_maxknownstrings = 0;
|
||||||
pr_stringssize = progs->numstrings;
|
pr_stringssize = progs->numstrings;
|
||||||
if (pr_knownstrings)
|
if (pr_knownstrings)
|
||||||
|
@ -1120,7 +1154,8 @@ void PR_LoadProgs (void)
|
||||||
pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
|
pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_alpha_supported = false; //johnfitz
|
for (u = 0; u < sizeof(pr_extfields)/sizeof(int); u++)
|
||||||
|
((int*)&pr_extfields)[u] = -1;
|
||||||
|
|
||||||
for (i = 0; i < progs->numfielddefs; i++)
|
for (i = 0; i < progs->numfielddefs; i++)
|
||||||
{
|
{
|
||||||
|
@ -1129,22 +1164,46 @@ void PR_LoadProgs (void)
|
||||||
Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
|
Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
|
||||||
pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
|
pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
|
||||||
pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
|
pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
|
||||||
|
|
||||||
//johnfitz -- detect alpha support in progs.dat
|
|
||||||
if (!strcmp(pr_strings + pr_fielddefs[i].s_name,"alpha"))
|
|
||||||
pr_alpha_supported = true;
|
|
||||||
//johnfitz
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < progs->numglobals; i++)
|
for (i = 0; i < progs->numglobals; i++)
|
||||||
((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
|
((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
|
||||||
|
|
||||||
pr_edict_size = progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t);
|
//spike: detect extended fields from progs
|
||||||
|
pr_extfields.items2 = ED_FindFieldOffset("items2");
|
||||||
|
pr_extfields.gravity = ED_FindFieldOffset("gravity");
|
||||||
|
pr_extfields.alpha = ED_FindFieldOffset("alpha");
|
||||||
|
pr_extfields.movement = ED_FindFieldOffset("movement");
|
||||||
|
pr_extfields.traileffectnum = ED_FindFieldOffset("traileffectnum");
|
||||||
|
pr_extfields.emiteffectnum = ED_FindFieldOffset("emiteffectnum");
|
||||||
|
pr_extfields.viewmodelforclient = ED_FindFieldOffset("viewmodelforclient");
|
||||||
|
pr_extfields.scale = ED_FindFieldOffset("scale");
|
||||||
|
pr_extfields.colormod = ED_FindFieldOffset("colormod");
|
||||||
|
pr_extfields.tag_entity = ED_FindFieldOffset("tag_entity");
|
||||||
|
pr_extfields.tag_index = ED_FindFieldOffset("tag_index");
|
||||||
|
pr_extfields.button3 = ED_FindFieldOffset("button3");
|
||||||
|
pr_extfields.button4 = ED_FindFieldOffset("button4");
|
||||||
|
pr_extfields.button5 = ED_FindFieldOffset("button5");
|
||||||
|
pr_extfields.button6 = ED_FindFieldOffset("button6");
|
||||||
|
pr_extfields.button7 = ED_FindFieldOffset("button7");
|
||||||
|
pr_extfields.button8 = ED_FindFieldOffset("button8");
|
||||||
|
pr_extfields.viewzoom = ED_FindFieldOffset("viewzoom");
|
||||||
|
pr_extfields.modelflags = ED_FindFieldOffset("modelflags");
|
||||||
|
|
||||||
|
i = progs->entityfields;
|
||||||
|
if (pr_extfields.emiteffectnum < 0)
|
||||||
|
pr_extfields.emiteffectnum = i++;
|
||||||
|
if (pr_extfields.traileffectnum < 0)
|
||||||
|
pr_extfields.traileffectnum = i++;
|
||||||
|
|
||||||
|
pr_edict_size = i * 4 + sizeof(edict_t) - sizeof(entvars_t);
|
||||||
// round off to next highest whole word address (esp for Alpha)
|
// round off to next highest whole word address (esp for Alpha)
|
||||||
// this ensures that pointers in the engine data area are always
|
// this ensures that pointers in the engine data area are always
|
||||||
// properly aligned
|
// properly aligned
|
||||||
pr_edict_size += sizeof(void *) - 1;
|
pr_edict_size += sizeof(void *) - 1;
|
||||||
pr_edict_size &= ~(sizeof(void *) - 1);
|
pr_edict_size &= ~(sizeof(void *) - 1);
|
||||||
|
|
||||||
|
PR_EnableExtensions(pr_globaldefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1159,6 +1218,7 @@ void PR_Init (void)
|
||||||
Cmd_AddCommand ("edicts", ED_PrintEdicts);
|
Cmd_AddCommand ("edicts", ED_PrintEdicts);
|
||||||
Cmd_AddCommand ("edictcount", ED_Count);
|
Cmd_AddCommand ("edictcount", ED_Count);
|
||||||
Cmd_AddCommand ("profile", PR_Profile_f);
|
Cmd_AddCommand ("profile", PR_Profile_f);
|
||||||
|
Cmd_AddCommand ("pr_dumpplatform", PR_DumpPlatform_f);
|
||||||
Cvar_RegisterVariable (&nomonsters);
|
Cvar_RegisterVariable (&nomonsters);
|
||||||
Cvar_RegisterVariable (&gamecfg);
|
Cvar_RegisterVariable (&gamecfg);
|
||||||
Cvar_RegisterVariable (&scratch1);
|
Cvar_RegisterVariable (&scratch1);
|
||||||
|
@ -1219,11 +1279,23 @@ const char *PR_GetString (int num)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
return pr_strings;
|
||||||
Host_Error("PR_GetString: invalid string offset %d\n", num);
|
Host_Error("PR_GetString: invalid string offset %d\n", num);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PR_ClearEngineString(int num)
|
||||||
|
{
|
||||||
|
if (num < 0 && num >= -pr_numknownstrings)
|
||||||
|
{
|
||||||
|
num = -1 - num;
|
||||||
|
pr_knownstrings[num] = NULL;
|
||||||
|
if (pr_freeknownstrings > num)
|
||||||
|
pr_freeknownstrings = num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int PR_SetEngineString (const char *s)
|
int PR_SetEngineString (const char *s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1244,19 +1316,22 @@ int PR_SetEngineString (const char *s)
|
||||||
}
|
}
|
||||||
// new unknown engine string
|
// new unknown engine string
|
||||||
//Con_DPrintf ("PR_SetEngineString: new engine string %p\n", s);
|
//Con_DPrintf ("PR_SetEngineString: new engine string %p\n", s);
|
||||||
#if 0
|
for (i = pr_freeknownstrings; ; i++)
|
||||||
for (i = 0; i < pr_numknownstrings; i++)
|
|
||||||
{
|
{
|
||||||
if (!pr_knownstrings[i])
|
if (i < pr_numknownstrings)
|
||||||
break;
|
{
|
||||||
|
if (pr_knownstrings[i])
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (i >= pr_maxknownstrings)
|
||||||
|
PR_AllocStringSlots();
|
||||||
|
pr_numknownstrings++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
pr_freeknownstrings = i+1;
|
||||||
// if (i >= pr_numknownstrings)
|
|
||||||
// {
|
|
||||||
if (i >= pr_maxknownstrings)
|
|
||||||
PR_AllocStringSlots();
|
|
||||||
pr_numknownstrings++;
|
|
||||||
// }
|
|
||||||
pr_knownstrings[i] = s;
|
pr_knownstrings[i] = s;
|
||||||
return -1 - i;
|
return -1 - i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,6 +371,8 @@ void PR_ExecuteProgram (func_t fnum)
|
||||||
|
|
||||||
f = &pr_functions[fnum];
|
f = &pr_functions[fnum];
|
||||||
|
|
||||||
|
//FIXME: if this is a builtin, then we're going to crash.
|
||||||
|
|
||||||
pr_trace = false;
|
pr_trace = false;
|
||||||
|
|
||||||
// make a stack frame
|
// make a stack frame
|
||||||
|
@ -383,7 +385,7 @@ void PR_ExecuteProgram (func_t fnum)
|
||||||
{
|
{
|
||||||
st++; /* next statement */
|
st++; /* next statement */
|
||||||
|
|
||||||
if (++profile > 100000)
|
if (++profile > 10000000) //spike -- was 100000
|
||||||
{
|
{
|
||||||
pr_xstatement = st - pr_statements;
|
pr_xstatement = st - pr_statements;
|
||||||
PR_RunError("runaway loop error");
|
PR_RunError("runaway loop error");
|
||||||
|
@ -612,7 +614,7 @@ void PR_ExecuteProgram (func_t fnum)
|
||||||
{ // Built-in function
|
{ // Built-in function
|
||||||
int i = -newf->first_statement;
|
int i = -newf->first_statement;
|
||||||
if (i >= pr_numbuiltins)
|
if (i >= pr_numbuiltins)
|
||||||
PR_RunError("Bad builtin call number %d", i);
|
i = 0; //just invoke the fixme builtin.
|
||||||
pr_builtins[i]();
|
pr_builtins[i]();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -42,7 +42,7 @@ typedef struct edict_s
|
||||||
qboolean free;
|
qboolean free;
|
||||||
link_t area; /* linked to a division node or leaf */
|
link_t area; /* linked to a division node or leaf */
|
||||||
|
|
||||||
int num_leafs;
|
unsigned int num_leafs;
|
||||||
int leafnums[MAX_ENT_LEAFS];
|
int leafnums[MAX_ENT_LEAFS];
|
||||||
|
|
||||||
entity_state_t baseline;
|
entity_state_t baseline;
|
||||||
|
@ -64,6 +64,7 @@ extern dfunction_t *pr_functions;
|
||||||
extern dstatement_t *pr_statements;
|
extern dstatement_t *pr_statements;
|
||||||
extern globalvars_t *pr_global_struct;
|
extern globalvars_t *pr_global_struct;
|
||||||
extern float *pr_globals; /* same as pr_global_struct */
|
extern float *pr_globals; /* same as pr_global_struct */
|
||||||
|
extern ddef_t *pr_fielddefs; //yay reflection.
|
||||||
|
|
||||||
extern int pr_edict_size; /* in bytes */
|
extern int pr_edict_size; /* in bytes */
|
||||||
|
|
||||||
|
@ -73,9 +74,28 @@ void PR_Init (void);
|
||||||
void PR_ExecuteProgram (func_t fnum);
|
void PR_ExecuteProgram (func_t fnum);
|
||||||
void PR_LoadProgs (void);
|
void PR_LoadProgs (void);
|
||||||
|
|
||||||
|
//from pr_ext.c
|
||||||
|
void PR_EnableExtensions(ddef_t *pr_globaldefs); //adds in the extra builtins etc
|
||||||
|
void PR_AutoCvarChanged(cvar_t *var); //updates the autocvar_ globals when their cvar is changed
|
||||||
|
void PR_ShutdownExtensions(void); //nooooes!
|
||||||
|
void PR_DumpPlatform_f(void); //console command: writes out a qsextensions.qc file
|
||||||
|
//special hacks...
|
||||||
|
int PF_SV_ForceParticlePrecache(const char *s);
|
||||||
|
int SV_Precache_Model(const char *s);
|
||||||
|
int SV_Precache_Sound(const char *s);
|
||||||
|
void PR_spawnfunc_misc_model(edict_t *self);
|
||||||
|
|
||||||
|
//from pr_edict, for pr_ext. reflection is messy.
|
||||||
|
qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s);
|
||||||
|
const char *PR_UglyValueString (int type, eval_t *val);
|
||||||
|
ddef_t *ED_FindField (const char *name);
|
||||||
|
ddef_t *ED_FindGlobal (const char *name);
|
||||||
|
dfunction_t *ED_FindFunction (const char *fn_name);
|
||||||
|
|
||||||
const char *PR_GetString (int num);
|
const char *PR_GetString (int num);
|
||||||
int PR_SetEngineString (const char *s);
|
int PR_SetEngineString (const char *s);
|
||||||
int PR_AllocString (int bufferlength, char **ptr);
|
int PR_AllocString (int bufferlength, char **ptr);
|
||||||
|
void PR_ClearEngineString(int num);
|
||||||
|
|
||||||
void PR_Profile_f (void);
|
void PR_Profile_f (void);
|
||||||
|
|
||||||
|
@ -138,7 +158,49 @@ FUNC_NORETURN void PR_RunError (const char *error, ...) FUNC_PRINTF(1,2);
|
||||||
void ED_PrintEdicts (void);
|
void ED_PrintEdicts (void);
|
||||||
void ED_PrintNum (int ent);
|
void ED_PrintNum (int ent);
|
||||||
|
|
||||||
eval_t *GetEdictFieldValue(edict_t *ed, const char *field);
|
eval_t *GetEdictFieldValue(edict_t *ed, int fldofs); //handles invalid offsets with a null
|
||||||
|
int ED_FindFieldOffset (const char *name);
|
||||||
|
|
||||||
|
|
||||||
|
//from pr_cmds, no longer static so that pr_ext can use them.
|
||||||
|
sizebuf_t *WriteDest (void);
|
||||||
|
char *PR_GetTempString (void);
|
||||||
|
char *PF_VarString (int first);
|
||||||
|
#define STRINGTEMP_BUFFERS 16
|
||||||
|
#define STRINGTEMP_LENGTH 1024
|
||||||
|
void PF_Fixme(void); //the 'unimplemented' builtin. woot.
|
||||||
|
|
||||||
|
extern struct pr_extfuncs_s
|
||||||
|
{ //various global qc entry points that might be called by the engine, if set.
|
||||||
|
func_t endframe;
|
||||||
|
func_t parseclientcommand;
|
||||||
|
} pr_extfuncs;
|
||||||
|
extern cvar_t pr_checkextension; //if 0, extensions are disabled (unless they'd be fatal, but they're still spammy)
|
||||||
|
|
||||||
|
extern struct pr_extfields_s
|
||||||
|
{ //various fields that might be wanted by the engine. -1 == invalid
|
||||||
|
//I should probably use preprocessor magic for this list or something
|
||||||
|
int items2; //float
|
||||||
|
int gravity; //float
|
||||||
|
int alpha; //float
|
||||||
|
int movement; //vector
|
||||||
|
int viewmodelforclient; //entity
|
||||||
|
int traileffectnum; //float
|
||||||
|
int emiteffectnum; //float
|
||||||
|
int scale; //float
|
||||||
|
int colormod; //vector
|
||||||
|
int tag_entity; //entity
|
||||||
|
int tag_index; //float
|
||||||
|
int button3; //float
|
||||||
|
int button4; //float
|
||||||
|
int button5; //float
|
||||||
|
int button6; //float
|
||||||
|
int button7; //float
|
||||||
|
int button8; //float
|
||||||
|
int viewzoom; //float
|
||||||
|
int modelflags; //float, the upper 8 bits of .effects
|
||||||
|
//REMEMBER TO ADD THESE TO qsextensions.qc AND pr_edict.c
|
||||||
|
} pr_extfields;
|
||||||
|
|
||||||
#endif /* _QUAKE_PROGS_H */
|
#endif /* _QUAKE_PROGS_H */
|
||||||
|
|
||||||
|
|
216
Quake/protocol.h
216
Quake/protocol.h
|
@ -25,9 +25,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
// protocol.h -- communications protocols
|
// protocol.h -- communications protocols
|
||||||
|
|
||||||
#define PROTOCOL_NETQUAKE 15 //johnfitz -- standard quake protocol
|
#define PROTOCOL_NETQUAKE 15 //johnfitz -- standard quake protocol
|
||||||
#define PROTOCOL_FITZQUAKE 666 //johnfitz -- added new protocol for fitzquake 0.85
|
//#define PROTOCOL_VERSION_H2 19
|
||||||
#define PROTOCOL_RMQ 999
|
//#define PROTOCOL_VERSION_NEHD 250
|
||||||
|
#define PROTOCOL_FITZQUAKE 666 //johnfitz -- added new protocol for fitzquake 0.85
|
||||||
|
#define PROTOCOL_RMQ 999
|
||||||
|
//#define PROTOCOL_VERSION_DP5 3502
|
||||||
|
//#define PROTOCOL_VERSION_DP6 3503
|
||||||
|
#define PROTOCOL_VERSION_DP7 3504
|
||||||
|
//#define PROTOCOL_VERSION_BJP1 10000
|
||||||
|
//#define PROTOCOL_VERSION_BJP2 10001
|
||||||
|
#define PROTOCOL_VERSION_BJP3 10002 //spike, note that this protocol is intentionally flawed to work around mods+writebytes - svc_staticsound is limited to 8bit indexes.
|
||||||
|
//#define PROTOCOL_FTE_PEXT1 (('F'<<0) + ('T'<<8) + ('E'<<16) + ('X' << 24)) //fte extensions, provides extensions to the underlying base protocol (like 666 or even 15).
|
||||||
|
#define PROTOCOL_FTE_PEXT2 (('F'<<0) + ('T'<<8) + ('E'<<16) + ('2' << 24)) //fte extensions, provides extensions to the underlying base protocol (like 666 or even 15).
|
||||||
|
|
||||||
// PROTOCOL_RMQ protocol flags
|
// PROTOCOL_RMQ protocol flags
|
||||||
#define PRFL_SHORTANGLE (1 << 1)
|
#define PRFL_SHORTANGLE (1 << 1)
|
||||||
|
@ -39,6 +49,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define PRFL_INT32COORD (1 << 7)
|
#define PRFL_INT32COORD (1 << 7)
|
||||||
#define PRFL_MOREFLAGS (1 << 31) // not supported
|
#define PRFL_MOREFLAGS (1 << 31) // not supported
|
||||||
|
|
||||||
|
// PROTOCOL_FTE_PEXT(1) flags
|
||||||
|
//mostly uninteresting, mostly superseeded by PEXT2_REPLACEMENTDELTAS...
|
||||||
|
|
||||||
|
// PROTOCOL_FTE_PEXT2 flags
|
||||||
|
#define PEXT2_PRYDONCURSOR 0x00000001 //a mouse cursor exposed to ssqc
|
||||||
|
#define PEXT2_VOICECHAT 0x00000002 //+voip or cl_voip_send 1; requires opus dll, and others to also have that same dll.
|
||||||
|
#define PEXT2_SETANGLEDELTA 0x00000004 //less annoying when teleporting.
|
||||||
|
#define PEXT2_REPLACEMENTDELTAS 0x00000008 //more compact entity deltas (can also be split across multiple packets)
|
||||||
|
#define PEXT2_MAXPLAYERS 0x00000010 //up to 255 player slots
|
||||||
|
#define PEXT2_PREDINFO 0x00000020 //provides input acks and reworks stats such that clc_clientdata becomes redundant.
|
||||||
|
#define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding, for more precise bboxes.
|
||||||
|
#define PEXT2_ACCEPTED_CLIENT (PEXT2_SUPPORTED_CLIENT|PEXT2_NEWSIZEENCODING|PEXT2_PRYDONCURSOR) //pext2 flags that we can parse, but don't want to advertise
|
||||||
|
#define PEXT2_SUPPORTED_CLIENT (PEXT2_SETANGLEDELTA|PEXT2_VOICECHAT|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO) //pext2 flags that we understand+support
|
||||||
|
#define PEXT2_SUPPORTED_SERVER ( PEXT2_VOICECHAT|PEXT2_REPLACEMENTDELTAS |PEXT2_PREDINFO)
|
||||||
|
|
||||||
// if the high bit of the servercmd is set, the low bits are fast update flags:
|
// if the high bit of the servercmd is set, the low bits are fast update flags:
|
||||||
#define U_MOREBITS (1<<0)
|
#define U_MOREBITS (1<<0)
|
||||||
#define U_ORIGIN1 (1<<1)
|
#define U_ORIGIN1 (1<<1)
|
||||||
|
@ -73,6 +98,59 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define U_TRANS (1<<15)
|
#define U_TRANS (1<<15)
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
|
||||||
|
|
||||||
|
//spike -- FTE Replacement Deltas
|
||||||
|
//first byte contains the stuff that's most likely to change constantly
|
||||||
|
#define UF_FRAME (1u<<0)
|
||||||
|
#define UF_ORIGINXY (1u<<1)
|
||||||
|
#define UF_ORIGINZ (1u<<2)
|
||||||
|
#define UF_ANGLESXZ (1u<<3)
|
||||||
|
#define UF_ANGLESY (1u<<4)
|
||||||
|
#define UF_EFFECTS (1u<<5)
|
||||||
|
#define UF_PREDINFO (1u<<6) /*ent is predicted, probably a player*/
|
||||||
|
#define UF_EXTEND1 (1u<<7)
|
||||||
|
|
||||||
|
/*stuff which is common on ent spawning*/
|
||||||
|
#define UF_RESET (1u<<8)
|
||||||
|
#define UF_16BIT (1u<<9) /*within this update, frame/skin/model is 16bit, not part of the deltaing itself*/
|
||||||
|
#define UF_MODEL (1u<<10)
|
||||||
|
#define UF_SKIN (1u<<11)
|
||||||
|
#define UF_COLORMAP (1u<<12)
|
||||||
|
#define UF_SOLID (1u<<13) /*encodes the size of the entity, so prediction can bump against it*/
|
||||||
|
#define UF_FLAGS (1u<<14) /*some extra flags like viewmodelforclient*/
|
||||||
|
#define UF_EXTEND2 (1u<<15)
|
||||||
|
|
||||||
|
/*the rest is optional extensions*/
|
||||||
|
#define UF_ALPHA (1u<<16) /*transparency*/
|
||||||
|
#define UF_SCALE (1u<<17) /*rescaling stuff, 1/16th*/
|
||||||
|
#define UF_BONEDATA (1u<<18) /*for ssqc control over skeletal models*/
|
||||||
|
#define UF_DRAWFLAGS (1u<<19) /*scale offsets and things*/
|
||||||
|
#define UF_TAGINFO (1u<<20) /*simple entity attachments, generally needs either md3s or skeletal models*/
|
||||||
|
#define UF_LIGHT (1u<<21) /*attaching rtlights to dynamic entities from ssqc*/
|
||||||
|
#define UF_TRAILEFFECT (1u<<22) /*attaches custom particle trails to entities, woo.*/
|
||||||
|
#define UF_EXTEND3 (1u<<23)
|
||||||
|
|
||||||
|
#define UF_COLORMOD (1u<<24) /*rgb tints. 1/16th*/
|
||||||
|
#define UF_GLOW (1u<<25) /*tbh only useful as an extra 'renderable' field for csqc...*/
|
||||||
|
#define UF_FATNESS (1u<<26) /*push the entity's normals out by this distance*/
|
||||||
|
#define UF_MODELINDEX2 (1u<<27) /*for lame visible weapon models, like q2. just adds a second ent at the same point*/
|
||||||
|
#define UF_GRAVITYDIR (1u<<28) /*yay prediction*/
|
||||||
|
#define UF_EFFECTS2 (1u<<29) /*effects is 16bit, or if both effects flags are set then 32bit*/
|
||||||
|
#define UF_UNUSED2 (1u<<30)
|
||||||
|
#define UF_UNUSED1 (1u<<31)
|
||||||
|
|
||||||
|
/*these flags are generally not deltaed as they're changing constantly*/
|
||||||
|
#define UFP_FORWARD (1u<<0)
|
||||||
|
#define UFP_SIDE (1u<<1)
|
||||||
|
#define UFP_UP (1u<<2)
|
||||||
|
#define UFP_MOVETYPE (1u<<3) /*deltaed*/
|
||||||
|
#define UFP_VELOCITYXY (1u<<4)
|
||||||
|
#define UFP_VELOCITYZ (1u<<5)
|
||||||
|
#define UFP_MSEC (1u<<6)
|
||||||
|
#define UFP_WEAPONFRAME_OLD (1u<<7) //no longer used. just a stat now that I rewrote stat deltas.
|
||||||
|
#define UFP_VIEWANGLE (1u<<7)
|
||||||
|
//spike
|
||||||
|
|
||||||
#define SU_VIEWHEIGHT (1<<0)
|
#define SU_VIEWHEIGHT (1<<0)
|
||||||
#define SU_IDEALPITCH (1<<1)
|
#define SU_IDEALPITCH (1<<1)
|
||||||
#define SU_PUNCH1 (1<<2)
|
#define SU_PUNCH1 (1<<2)
|
||||||
|
@ -107,19 +185,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define SU_UNUSED30 (1<<30)
|
#define SU_UNUSED30 (1<<30)
|
||||||
#define SU_EXTEND3 (1<<31) // another byte to follow, future expansion
|
#define SU_EXTEND3 (1<<31) // another byte to follow, future expansion
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
//spike dp crap
|
||||||
|
#define DPSU_PUNCHVEC1 (1<<16)
|
||||||
|
#define DPSU_PUNCHVEC2 (1<<17)
|
||||||
|
#define DPSU_PUNCHVEC3 (1<<18)
|
||||||
|
#define DPSU_VIEWZOOM (1<<19) // byte factor (0 = 0.0 (not valid), 255 = 1.0)
|
||||||
|
//spike
|
||||||
|
|
||||||
// a sound with no channel is a local only sound
|
// a sound with no channel is a local only sound
|
||||||
#define SND_VOLUME (1<<0) // a byte
|
#define SND_VOLUME (1<<0) // a byte
|
||||||
#define SND_ATTENUATION (1<<1) // a byte
|
#define SND_ATTENUATION (1<<1) // a byte
|
||||||
#define SND_LOOPING (1<<2) // a long
|
//#define SND_LOOPING (1<<2) // a long (unused in vanilla)
|
||||||
|
|
||||||
#define DEFAULT_SOUND_PACKET_VOLUME 255
|
#define DEFAULT_SOUND_PACKET_VOLUME 255
|
||||||
#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
|
#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
|
||||||
|
|
||||||
//johnfitz -- PROTOCOL_FITZQUAKE -- new bits
|
//johnfitz -- PROTOCOL_FITZQUAKE -- new bits
|
||||||
#define SND_LARGEENTITY (1<<3) // a short + byte (instead of just a short)
|
#define SND_LARGEENTITY (1<<3) // a short + byte (instead of just a short)
|
||||||
#define SND_LARGESOUND (1<<4) // a short soundindex (instead of a byte)
|
#define SND_LARGESOUND (1<<4) // a short soundindex (instead of a byte)
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
//spike -- parsing, but not using at this time
|
||||||
|
#define SND_FTE_MOREFLAGS (1<<2) // a byte, for channel flags
|
||||||
|
#define SND_DP_PITCH (1<<5) //dp uses this for pitch...
|
||||||
|
#define SND_FTE_TIMEOFS (1<<6) //signed short, in milliseconds.
|
||||||
|
#define SND_FTE_PITCHADJ (1<<7) //a byte (speed percent (0=100%))
|
||||||
|
#define SND_FTE_VELOCITY (1<<8) //3 shorts (1/8th), for doppler or whatever.
|
||||||
|
//spike
|
||||||
|
|
||||||
//johnfitz -- PROTOCOL_FITZQUAKE -- flags for entity baseline messages
|
//johnfitz -- PROTOCOL_FITZQUAKE -- flags for entity baseline messages
|
||||||
#define B_LARGEMODEL (1<<0) // modelindex is short instead of byte
|
#define B_LARGEMODEL (1<<0) // modelindex is short instead of byte
|
||||||
|
@ -178,6 +269,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define svc_damage 19
|
#define svc_damage 19
|
||||||
#define svc_spawnstatic 20
|
#define svc_spawnstatic 20
|
||||||
//#define svc_spawnbinary 21
|
//#define svc_spawnbinary 21
|
||||||
|
#define svcfte_spawnstatic2 21
|
||||||
#define svc_spawnbaseline 22
|
#define svc_spawnbaseline 22
|
||||||
#define svc_temp_entity 23
|
#define svc_temp_entity 23
|
||||||
#define svc_setpause 24 // [byte] on / off
|
#define svc_setpause 24 // [byte] on / off
|
||||||
|
@ -201,6 +293,31 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define svc_spawnstaticsound2 44 // [coord3] [short] samp [byte] vol [byte] aten
|
#define svc_spawnstaticsound2 44 // [coord3] [short] samp [byte] vol [byte] aten
|
||||||
//johnfitz
|
//johnfitz
|
||||||
|
|
||||||
|
//spike -- some extensions for particles.
|
||||||
|
//some extra stuff for fte's pext2_replacementdeltas, including stats
|
||||||
|
//fte reuses the dp svcs for nq (instead of qw-specific ones), at least where the protocol is identical. this should make dpp7 support a little easier if you ever want to implement that.
|
||||||
|
//dp has a tendancy to use the svcs even when told to use protocol 15, so supporting them helps there too.
|
||||||
|
#define svcdp_downloaddata 50
|
||||||
|
#define svcdp_updatestatbyte 51
|
||||||
|
#define svcdp_effect 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
|
||||||
|
#define svcdp_effect2 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
|
||||||
|
#define svcdp_precache 54 // [short] precacheindex [string] filename. index&0x8000 = sound, 0x4000 = particle, 0xc000 = reserved (probably to reclaim these bits eventually), otherwise model.
|
||||||
|
#define svcdp_spawnbaseline2 55
|
||||||
|
#define svcdp_spawnstatic2 56
|
||||||
|
#define svcdp_entities 57
|
||||||
|
#define svcdp_csqcentities 58
|
||||||
|
#define svcdp_spawnstaticsound2 59 // [coord3] [short] samp [byte] vol [byte] aten
|
||||||
|
#define svcdp_trailparticles 60 // [short] entnum [short] effectnum [vector] start [vector] end
|
||||||
|
#define svcdp_pointparticles 61 // [short] effectnum [vector] start [vector] velocity [short] count
|
||||||
|
#define svcdp_pointparticles1 62 // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1
|
||||||
|
#define svcfte_spawnbaseline2 66
|
||||||
|
#define svcfte_updatestatstring 78
|
||||||
|
#define svcfte_updatestatfloat 79
|
||||||
|
#define svcfte_voicechat 84
|
||||||
|
#define svcfte_setangledelta 85
|
||||||
|
#define svcfte_updateentities 86
|
||||||
|
//spike -- end
|
||||||
|
|
||||||
//
|
//
|
||||||
// client to server
|
// client to server
|
||||||
//
|
//
|
||||||
|
@ -209,6 +326,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define clc_disconnect 2
|
#define clc_disconnect 2
|
||||||
#define clc_move 3 // [usercmd_t]
|
#define clc_move 3 // [usercmd_t]
|
||||||
#define clc_stringcmd 4 // [string] message
|
#define clc_stringcmd 4 // [string] message
|
||||||
|
#define clcdp_ackframe 50 // [long] frame sequence. reused by fte replacement deltas
|
||||||
|
#define clcdp_ackdownloaddata 51
|
||||||
|
#define clcfte_voicechat 83 /*spike*/
|
||||||
|
|
||||||
//
|
//
|
||||||
// temp entity events
|
// temp entity events
|
||||||
|
@ -231,17 +351,93 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define TE_BEAM 13
|
#define TE_BEAM 13
|
||||||
// PGM 01/21/97
|
// PGM 01/21/97
|
||||||
|
|
||||||
typedef struct
|
//spike, these are from nehahra. misc servers might expect us to support them
|
||||||
|
#define TENEH_EXPLOSION3 16 // [vector] origin [coord] red [coord] green [coord] blue
|
||||||
|
#define TENEH_LIGHTNING4 17 // [string] model [entity] entity [vector] start [vector] end
|
||||||
|
//spike, quakeworld mods have different explosion+gunshot behaviour, which we might be expected to support
|
||||||
|
#define TEFTE_EXPLOSION_SPRITE 20 //for compat with qw mods
|
||||||
|
#define TEFTE_GUNSHOT_COUNT 21 //for compat with qw mods
|
||||||
|
//spike, these are the various te effects from DP. ideally people would just use pointparticles so these are somewhat considered legacy.
|
||||||
|
#define TEDP_BLOOD 50
|
||||||
|
#define TEDP_SPARK 51
|
||||||
|
#define TEDP_BLOODSHOWER 52
|
||||||
|
#define TEDP_EXPLOSIONRGB 53
|
||||||
|
#define TEDP_PARTICLECUBE 54
|
||||||
|
#define TEDP_PARTICLERAIN 55 // [vector] min [vector] max [vector] dir [short] count [byte] color
|
||||||
|
#define TEDP_PARTICLESNOW 56 // [vector] min [vector] max [vector] dir [short] count [byte] color
|
||||||
|
#define TEDP_GUNSHOTQUAD 57 // [vector] origin
|
||||||
|
#define TEDP_SPIKEQUAD 58 // [vector] origin
|
||||||
|
#define TEDP_SUPERSPIKEQUAD 59 // [vector] origin
|
||||||
|
#define TEDP_EXPLOSIONQUAD 70 // [vector] origin
|
||||||
|
#define TEDP_SMALLFLASH 72 // [vector] origin
|
||||||
|
#define TEDP_CUSTOMFLASH 73
|
||||||
|
#define TEDP_FLAMEJET 74
|
||||||
|
#define TEDP_PLASMABURN 75
|
||||||
|
#define TEDP_TEI_G3 76
|
||||||
|
#define TEDP_SMOKE 77
|
||||||
|
#define TEDP_TEI_BIGEXPLOSION 78
|
||||||
|
#define TEDP_TEI_PLASMAHIT 79
|
||||||
|
//end spike
|
||||||
|
|
||||||
|
// entity effects
|
||||||
|
|
||||||
|
#define EF_BRIGHTFIELD 1
|
||||||
|
#define EF_MUZZLEFLASH 2
|
||||||
|
#define EF_BRIGHTLIGHT 4
|
||||||
|
#define EF_DIMLIGHT 8
|
||||||
|
//#define EF_NODRAW 16
|
||||||
|
//#define EF_ADDITIVE 32
|
||||||
|
//#define EF_BLUE 64
|
||||||
|
//#define EF_RED 128
|
||||||
|
//#define EFDP_NOGUNBOB (1u<<8)
|
||||||
|
#define EF_FULLBRIGHT (1u<<9)
|
||||||
|
//#define EFDP_PART_FLAME (1u<<10)
|
||||||
|
//#define EFDP_PART_STARDUST (1u<<11)
|
||||||
|
#define EF_NOSHADOW (1u<<12)
|
||||||
|
//#define EF_NODEPTHTEST (1u<<13)
|
||||||
|
//#define EFDP_SELECTABLE (1u<<14)
|
||||||
|
//#define EFDP_DOUBLESIDED (1u<<15)
|
||||||
|
//#define EFDP_NOSELFSHADOW (1u<<16)
|
||||||
|
//#define EFDP_DYNAMICMODELLIGHT (1u<<17)
|
||||||
|
//#define EF_GREEN (1u<<18)
|
||||||
|
//#define EF_UNUSED (1u<<19)
|
||||||
|
//#define EF_RESTARTANIM_BIT (1u<<20) //reset model lerps over toggles
|
||||||
|
//#define EF_TELEPORT_BIT (1u<<21) //reset origin lerps over toggles
|
||||||
|
//#define EFDP_LOWPRECISION (1u<<22)
|
||||||
|
#define EF_NOMODELFLAGS (1u<<23)
|
||||||
|
//24-31 are used for modelflag overrides (rotate, legacy trails, etc)
|
||||||
|
|
||||||
|
typedef struct entity_state_s
|
||||||
{
|
{
|
||||||
vec3_t origin;
|
vec3_t origin;
|
||||||
vec3_t angles;
|
vec3_t angles;
|
||||||
unsigned short modelindex; //johnfitz -- was int
|
unsigned short modelindex; //johnfitz -- was int
|
||||||
unsigned short frame; //johnfitz -- was int
|
unsigned short frame; //johnfitz -- was int
|
||||||
unsigned char colormap; //johnfitz -- was int
|
unsigned int effects;
|
||||||
unsigned char skin; //johnfitz -- was int
|
unsigned char colormap; //johnfitz -- was int
|
||||||
|
unsigned char skin; //johnfitz -- was int
|
||||||
|
unsigned char scale; //spike -- *16
|
||||||
|
unsigned char pmovetype; //spike
|
||||||
|
unsigned short traileffectnum; //spike -- for qc-defined particle trails. typically evilly used for things that are not trails.
|
||||||
|
unsigned short emiteffectnum; //spike -- for qc-defined particle trails. typically evilly used for things that are not trails.
|
||||||
|
short velocity[3]; //spike -- the player's velocity.
|
||||||
|
unsigned char eflags;
|
||||||
|
unsigned char tagindex;
|
||||||
|
unsigned short tagentity;
|
||||||
|
// unsigned short pad;
|
||||||
|
unsigned char colormod[3]; //spike -- entity tints, *32
|
||||||
unsigned char alpha; //johnfitz -- added
|
unsigned char alpha; //johnfitz -- added
|
||||||
int effects;
|
|
||||||
} entity_state_t;
|
} entity_state_t;
|
||||||
|
#define EFLAGS_STEP 1
|
||||||
|
//#define EFLAGS_GLOWTRAIL 2
|
||||||
|
#define EFLAGS_VIEWMODEL 4 //does not appear in reflections/third person. attached to the view.
|
||||||
|
#define EFLAGS_EXTERIORMODEL 8 //only appears in reflections/third person
|
||||||
|
//#define EFLAGS_ 16
|
||||||
|
//#define EFLAGS_COLOURMAPPED 32 //.colormap=1024|(top<<4)|bottom), instead of a player number
|
||||||
|
//#define EFLAGS_ 64
|
||||||
|
#define EFLAGS_ONGROUND 128 //for bobbing more than anything else. *sigh*.
|
||||||
|
|
||||||
|
extern entity_state_t nullentitystate; //note: not all null.
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,9 +105,6 @@ void S_UnblockSound (void);
|
||||||
|
|
||||||
sfx_t *S_PrecacheSound (const char *sample);
|
sfx_t *S_PrecacheSound (const char *sample);
|
||||||
void S_TouchSound (const char *sample);
|
void S_TouchSound (const char *sample);
|
||||||
void S_ClearPrecache (void);
|
|
||||||
void S_BeginPrecaching (void);
|
|
||||||
void S_EndPrecaching (void);
|
|
||||||
void S_PaintChannels (int endtime);
|
void S_PaintChannels (int endtime);
|
||||||
void S_InitPaintChannels (void);
|
void S_InitPaintChannels (void);
|
||||||
|
|
||||||
|
@ -147,10 +144,10 @@ void SNDDMA_UnblockSound(void);
|
||||||
* ====================================================================
|
* ====================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MAX_CHANNELS 1024 // ericw -- was 512 /* johnfitz -- was 128 */
|
//#define MAX_CHANNELS 1024 // spike -- made this obsolete. ericw -- was 512 /* johnfitz -- was 128 */
|
||||||
#define MAX_DYNAMIC_CHANNELS 128 /* johnfitz -- was 8 */
|
#define MAX_DYNAMIC_CHANNELS 128 /* johnfitz -- was 8 */
|
||||||
|
|
||||||
extern channel_t snd_channels[MAX_CHANNELS];
|
extern channel_t *snd_channels;
|
||||||
/* 0 to MAX_DYNAMIC_CHANNELS-1 = normal entity sounds
|
/* 0 to MAX_DYNAMIC_CHANNELS-1 = normal entity sounds
|
||||||
* MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc
|
* MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc
|
||||||
* MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds
|
* MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds
|
||||||
|
@ -158,11 +155,14 @@ extern channel_t snd_channels[MAX_CHANNELS];
|
||||||
|
|
||||||
extern volatile dma_t *shm;
|
extern volatile dma_t *shm;
|
||||||
|
|
||||||
|
extern int max_channels;
|
||||||
extern int total_channels;
|
extern int total_channels;
|
||||||
extern int soundtime;
|
extern int soundtime;
|
||||||
extern int paintedtime;
|
extern int paintedtime;
|
||||||
extern int s_rawend;
|
extern int s_rawend;
|
||||||
|
|
||||||
|
extern float voicevolumescale;
|
||||||
|
|
||||||
extern vec3_t listener_origin;
|
extern vec3_t listener_origin;
|
||||||
extern vec3_t listener_forward;
|
extern vec3_t listener_forward;
|
||||||
extern vec3_t listener_right;
|
extern vec3_t listener_right;
|
||||||
|
|
|
@ -48,10 +48,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
// combined version string like "0.92.1-beta1"
|
// combined version string like "0.92.1-beta1"
|
||||||
#define QUAKESPASM_VER_STRING QS_STRINGIFY(QUAKESPASM_VERSION) "." QS_STRINGIFY(QUAKESPASM_VER_PATCH) QUAKESPASM_VER_SUFFIX
|
#define QUAKESPASM_VER_STRING QS_STRINGIFY(QUAKESPASM_VERSION) "." QS_STRINGIFY(QUAKESPASM_VER_PATCH) QUAKESPASM_VER_SUFFIX
|
||||||
|
|
||||||
|
#define ENGINE_NAME_AND_VER "QSS" " " QUAKESPASM_VER_STRING
|
||||||
|
|
||||||
//define PARANOID // speed sapping error checking
|
//define PARANOID // speed sapping error checking
|
||||||
|
|
||||||
#define GAMENAME "id1" // directory to look in by default
|
#define GAMENAME "id1" // directory to look in by default
|
||||||
|
|
||||||
|
#define PSET_SCRIPT //enable the scriptable particle system (poorly ported from FTE)
|
||||||
|
#define PSET_SCRIPT_EFFECTINFO //scripted particle system can load dp's effects
|
||||||
|
|
||||||
|
|
||||||
#include "q_stdinc.h"
|
#include "q_stdinc.h"
|
||||||
|
|
||||||
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
|
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
|
||||||
|
@ -88,15 +94,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
//
|
//
|
||||||
// per-level limits
|
// per-level limits
|
||||||
//
|
//
|
||||||
#define MIN_EDICTS 256 // johnfitz -- lowest allowed value for max_edicts cvar
|
#define MIN_EDICTS 256 // johnfitz -- lowest allowed value for max_edicts cvar
|
||||||
#define MAX_EDICTS 32000 // johnfitz -- highest allowed value for max_edicts cvar
|
#define MAX_EDICTS 32000 // johnfitz -- highest allowed value for max_edicts cvar
|
||||||
// ents past 8192 can't play sounds in the standard protocol
|
// ents past 8192 can't play sounds in the standard protocol
|
||||||
#define MAX_LIGHTSTYLES 64
|
#define MAX_LIGHTSTYLES 255 //spike -- file format max of 255, increasing will break saved games.
|
||||||
#define MAX_MODELS 2048 // johnfitz -- was 256
|
#define MAX_MODELS 4096 // johnfitz -- was 256
|
||||||
#define MAX_SOUNDS 2048 // johnfitz -- was 256
|
#define MAX_SOUNDS 2048 // johnfitz -- was 256
|
||||||
|
#define MAX_PARTICLETYPES 2048
|
||||||
|
|
||||||
#define SAVEGAME_COMMENT_LENGTH 39
|
#define SAVEGAME_COMMENT_LENGTH 39
|
||||||
|
|
||||||
|
#define MAX_LIGHTSTYLES_VANILLA 64
|
||||||
#define MAX_STYLESTRING 64
|
#define MAX_STYLESTRING 64
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -119,6 +127,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret
|
#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret
|
||||||
#define STAT_MONSTERS 14 // bumped by svc_killedmonster
|
#define STAT_MONSTERS 14 // bumped by svc_killedmonster
|
||||||
|
|
||||||
|
#define STAT_ITEMS 15 //replaces clc_clientdata info
|
||||||
|
#define STAT_VIEWHEIGHT 16 //replaces clc_clientdata info
|
||||||
|
//#define STAT_TIME 17 //zquake, redundant for nq.
|
||||||
|
//#define STAT_MATCHSTARTTIME 18
|
||||||
|
//#define STAT_VIEW2 20
|
||||||
|
#define STAT_VIEWZOOM 21 // DP
|
||||||
|
#define STAT_IDEALPITCH 25 //nq-emu
|
||||||
|
#define STAT_PUNCHANGLE_X 26 //nq-emu
|
||||||
|
#define STAT_PUNCHANGLE_Y 27 //nq-emu
|
||||||
|
#define STAT_PUNCHANGLE_Z 28 //nq-emu
|
||||||
|
|
||||||
// stock defines
|
// stock defines
|
||||||
//
|
//
|
||||||
#define IT_SHOTGUN 1
|
#define IT_SHOTGUN 1
|
||||||
|
@ -186,7 +205,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
//===========================================
|
//===========================================
|
||||||
|
|
||||||
#define MAX_SCOREBOARD 16
|
#define MAX_SCOREBOARD 255
|
||||||
#define MAX_SCOREBOARDNAME 32
|
#define MAX_SCOREBOARDNAME 32
|
||||||
|
|
||||||
#define SOUND_CHANNELS 8
|
#define SOUND_CHANNELS 8
|
||||||
|
@ -219,6 +238,7 @@ typedef struct
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
|
|
||||||
|
#include "snd_voip.h"
|
||||||
#include "progs.h"
|
#include "progs.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
|
@ -316,6 +336,9 @@ void Host_ClientCommands (const char *fmt, ...) FUNC_PRINTF(1,2);
|
||||||
void Host_ShutdownServer (qboolean crash);
|
void Host_ShutdownServer (qboolean crash);
|
||||||
void Host_WriteConfiguration (void);
|
void Host_WriteConfiguration (void);
|
||||||
|
|
||||||
|
void Host_AppendDownloadData(client_t *client, sizebuf_t *buf);
|
||||||
|
void Host_DownloadAck(client_t *client);
|
||||||
|
|
||||||
void ExtraMaps_Init (void);
|
void ExtraMaps_Init (void);
|
||||||
void Modlist_Init (void);
|
void Modlist_Init (void);
|
||||||
void DemoList_Init (void);
|
void DemoList_Init (void);
|
||||||
|
|
673
Quake/r_alias.c
673
Quake/r_alias.c
|
@ -94,10 +94,15 @@ Returns the offset of the first vertex's meshxyz_t.xyz in the vbo for the given
|
||||||
model and pose.
|
model and pose.
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static void *GLARB_GetXYZOffset (aliashdr_t *hdr, int pose)
|
static void *GLARB_GetXYZOffset_MDL (aliashdr_t *hdr, int pose)
|
||||||
{
|
{
|
||||||
const int xyzoffs = offsetof (meshxyz_t, xyz);
|
const size_t xyzoffs = offsetof (meshxyz_mdl_t, xyz);
|
||||||
return (void *) (currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + xyzoffs);
|
return currententity->model->meshvboptr+(hdr->vbovertofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_mdl_t)) + xyzoffs);
|
||||||
|
}
|
||||||
|
static void *GLARB_GetXYZOffset_MD3 (aliashdr_t *hdr, int pose)
|
||||||
|
{
|
||||||
|
const size_t xyzoffs = offsetof (meshxyz_md3_t, xyz);
|
||||||
|
return currententity->model->meshvboptr+(hdr->vbovertofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_md3_t)) + xyzoffs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -108,10 +113,15 @@ Returns the offset of the first vertex's meshxyz_t.normal in the vbo for the
|
||||||
given model and pose.
|
given model and pose.
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static void *GLARB_GetNormalOffset (aliashdr_t *hdr, int pose)
|
static void *GLARB_GetNormalOffset_MDL (aliashdr_t *hdr, int pose)
|
||||||
{
|
{
|
||||||
const int normaloffs = offsetof (meshxyz_t, normal);
|
const size_t normaloffs = offsetof (meshxyz_mdl_t, normal);
|
||||||
return (void *)(currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + normaloffs);
|
return currententity->model->meshvboptr+(hdr->vbovertofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_mdl_t)) + normaloffs);
|
||||||
|
}
|
||||||
|
static void *GLARB_GetNormalOffset_MD3 (aliashdr_t *hdr, int pose)
|
||||||
|
{
|
||||||
|
const size_t normaloffs = offsetof (meshxyz_md3_t, normal);
|
||||||
|
return currententity->model->meshvboptr+(hdr->vbovertofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_md3_t)) + normaloffs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -249,12 +259,23 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
||||||
GL_EnableVertexAttribArrayFunc (pose1NormalAttrIndex);
|
GL_EnableVertexAttribArrayFunc (pose1NormalAttrIndex);
|
||||||
GL_EnableVertexAttribArrayFunc (pose2NormalAttrIndex);
|
GL_EnableVertexAttribArrayFunc (pose2NormalAttrIndex);
|
||||||
|
|
||||||
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, 0, (void *)(intptr_t)currententity->model->vbostofs);
|
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||||
GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_t), GLARB_GetXYZOffset (paliashdr, lerpdata.pose1));
|
if (paliashdr->posevertssize == 1)
|
||||||
GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_t), GLARB_GetXYZOffset (paliashdr, lerpdata.pose2));
|
{
|
||||||
// GL_TRUE to normalize the signed bytes to [-1 .. 1]
|
GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_mdl_t), GLARB_GetXYZOffset_MDL (paliashdr, lerpdata.pose1));
|
||||||
GL_VertexAttribPointerFunc (pose1NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_t), GLARB_GetNormalOffset (paliashdr, lerpdata.pose1));
|
GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_mdl_t), GLARB_GetXYZOffset_MDL (paliashdr, lerpdata.pose2));
|
||||||
GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_t), GLARB_GetNormalOffset (paliashdr, lerpdata.pose2));
|
// GL_TRUE to normalize the signed bytes to [-1 .. 1]
|
||||||
|
GL_VertexAttribPointerFunc (pose1NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_mdl_t), GLARB_GetNormalOffset_MDL (paliashdr, lerpdata.pose1));
|
||||||
|
GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_mdl_t), GLARB_GetNormalOffset_MDL (paliashdr, lerpdata.pose2));
|
||||||
|
}
|
||||||
|
else if (paliashdr->posevertssize == 2)
|
||||||
|
{
|
||||||
|
GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_SHORT, GL_FALSE, sizeof (meshxyz_md3_t), GLARB_GetXYZOffset_MD3 (paliashdr, lerpdata.pose1));
|
||||||
|
GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_SHORT, GL_FALSE, sizeof (meshxyz_md3_t), GLARB_GetXYZOffset_MD3 (paliashdr, lerpdata.pose2));
|
||||||
|
// GL_TRUE to normalize the signed bytes to [-1 .. 1]
|
||||||
|
GL_VertexAttribPointerFunc (pose1NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_md3_t), GLARB_GetNormalOffset_MD3 (paliashdr, lerpdata.pose1));
|
||||||
|
GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_md3_t), GLARB_GetNormalOffset_MD3 (paliashdr, lerpdata.pose2));
|
||||||
|
}
|
||||||
|
|
||||||
// set uniforms
|
// set uniforms
|
||||||
GL_Uniform1fFunc (blendLoc, blend);
|
GL_Uniform1fFunc (blendLoc, blend);
|
||||||
|
@ -277,7 +298,7 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw
|
// draw
|
||||||
glDrawElements (GL_TRIANGLES, paliashdr->numindexes, GL_UNSIGNED_SHORT, (void *)(intptr_t)currententity->model->vboindexofs);
|
glDrawElements (GL_TRIANGLES, paliashdr->numindexes, GL_UNSIGNED_SHORT, currententity->model->meshindexesvboptr+paliashdr->eboofs);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
GL_DisableVertexAttribArrayFunc (texCoordsAttrIndex);
|
GL_DisableVertexAttribArrayFunc (texCoordsAttrIndex);
|
||||||
|
@ -294,111 +315,215 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
GL_DrawAliasFrame -- johnfitz -- rewritten to support colored light, lerping, entalpha, multitexture, and r_drawflat
|
GL_DrawAliasFrame
|
||||||
|
-- johnfitz -- rewritten to support colored light, lerping, entalpha, multitexture, and r_drawflat
|
||||||
|
-- spike -- rewritten to use vertex arrays, which should be slightly faster thanks to less branches+gl calls (note that this requires gl1.1, which we depend on anyway for texture objects, and is pretty much universal.
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata)
|
void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata)
|
||||||
{
|
{
|
||||||
float vertcolor[4];
|
static vec3_t vpos[65536];
|
||||||
trivertx_t *verts1, *verts2;
|
static vec4_t vc[65536];
|
||||||
int *commands;
|
int i;
|
||||||
int count;
|
|
||||||
float u,v;
|
|
||||||
float blend, iblend;
|
float blend, iblend;
|
||||||
qboolean lerping;
|
|
||||||
|
|
||||||
if (lerpdata.pose1 != lerpdata.pose2)
|
if (lerpdata.pose1 != lerpdata.pose2)
|
||||||
{
|
{
|
||||||
lerping = true;
|
|
||||||
verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
|
|
||||||
verts2 = verts1;
|
|
||||||
verts1 += lerpdata.pose1 * paliashdr->poseverts;
|
|
||||||
verts2 += lerpdata.pose2 * paliashdr->poseverts;
|
|
||||||
blend = lerpdata.blend;
|
blend = lerpdata.blend;
|
||||||
iblend = 1.0f - blend;
|
iblend = 1.0-blend;
|
||||||
}
|
}
|
||||||
else // poses the same means either 1. the entity has paused its animation, or 2. r_lerpmodels is disabled
|
else // poses the same means either 1. the entity has paused its animation, or 2. r_lerpmodels is disabled
|
||||||
{
|
{
|
||||||
lerping = false;
|
blend = 1;
|
||||||
verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
|
iblend = 0;
|
||||||
verts2 = verts1; // avoid bogus compiler warning
|
|
||||||
verts1 += lerpdata.pose1 * paliashdr->poseverts;
|
|
||||||
blend = iblend = 0; // avoid bogus compiler warning
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commands = (int *)((byte *)paliashdr + paliashdr->commands);
|
//pose1*iblend + pose2*blend
|
||||||
|
|
||||||
vertcolor[3] = entalpha; //never changes, so there's no need to put this inside the loop
|
if (shading && r_drawflat_cheatsafe)
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
{
|
||||||
// get the vertex count and primitive type
|
shading = false;
|
||||||
count = *commands++;
|
glColor4f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0, entalpha);
|
||||||
if (!count)
|
}
|
||||||
break; // done
|
|
||||||
|
|
||||||
if (count < 0)
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
{
|
if (paliashdr->posevertssize == 1)
|
||||||
count = -count;
|
{
|
||||||
glBegin (GL_TRIANGLE_FAN);
|
trivertx_t *verts1 = (trivertx_t*)((byte *)paliashdr + paliashdr->vertexes) + lerpdata.pose1 * paliashdr->numverts_vbo;
|
||||||
}
|
trivertx_t *verts2 = (trivertx_t*)((byte *)paliashdr + paliashdr->vertexes) + lerpdata.pose2 * paliashdr->numverts_vbo;
|
||||||
else
|
|
||||||
glBegin (GL_TRIANGLE_STRIP);
|
|
||||||
|
|
||||||
do
|
if (iblend)
|
||||||
{
|
{
|
||||||
u = ((float *)commands)[0];
|
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||||
v = ((float *)commands)[1];
|
|
||||||
if (mtexenabled)
|
|
||||||
{
|
{
|
||||||
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, u, v);
|
vpos[i][0] = verts1[i].v[0] * iblend + blend * verts2[i].v[0];
|
||||||
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, u, v);
|
vpos[i][1] = verts1[i].v[1] * iblend + blend * verts2[i].v[1];
|
||||||
|
vpos[i][2] = verts1[i].v[2] * iblend + blend * verts2[i].v[2];
|
||||||
}
|
}
|
||||||
else
|
GL_BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||||
glTexCoord2f (u, v);
|
glVertexPointer(3, GL_FLOAT, sizeof (vpos[0]), vpos);
|
||||||
|
|
||||||
commands += 2;
|
|
||||||
|
|
||||||
if (shading)
|
if (shading)
|
||||||
{
|
{
|
||||||
if (r_drawflat_cheatsafe)
|
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||||
{
|
{
|
||||||
srand(count * (unsigned int)(src_offset_t)commands);
|
vc[i][0] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[0];
|
||||||
glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0);
|
vc[i][1] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[1];
|
||||||
|
vc[i][2] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[2];
|
||||||
|
vc[i][3] = entalpha;
|
||||||
}
|
}
|
||||||
else if (lerping)
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glColorPointer(4, GL_FLOAT, sizeof(*vc), vc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (shading)
|
||||||
|
{
|
||||||
|
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||||
{
|
{
|
||||||
vertcolor[0] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[0];
|
vc[i][0] = shadedots[verts2->lightnormalindex] * lightcolor[0];
|
||||||
vertcolor[1] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[1];
|
vc[i][1] = shadedots[verts2->lightnormalindex] * lightcolor[1];
|
||||||
vertcolor[2] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[2];
|
vc[i][2] = shadedots[verts2->lightnormalindex] * lightcolor[2];
|
||||||
glColor4fv (vertcolor);
|
vc[i][3] = entalpha;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vertcolor[0] = shadedots[verts1->lightnormalindex] * lightcolor[0];
|
|
||||||
vertcolor[1] = shadedots[verts1->lightnormalindex] * lightcolor[1];
|
|
||||||
vertcolor[2] = shadedots[verts1->lightnormalindex] * lightcolor[2];
|
|
||||||
glColor4fv (vertcolor);
|
|
||||||
}
|
}
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
GL_BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||||
|
glColorPointer(4, GL_FLOAT, 0, vc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lerping)
|
//glVertexPointer may not take GL_UNSIGNED_BYTE, which means we can't use our vbos. attribute 0 MAY be vertex coords, but I don't want to depend on that.
|
||||||
|
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||||
{
|
{
|
||||||
glVertex3f (verts1->v[0]*iblend + verts2->v[0]*blend,
|
vpos[i][0] = verts2[i].v[0];
|
||||||
verts1->v[1]*iblend + verts2->v[1]*blend,
|
vpos[i][1] = verts2[i].v[1];
|
||||||
verts1->v[2]*iblend + verts2->v[2]*blend);
|
vpos[i][2] = verts2[i].v[2];
|
||||||
verts1++;
|
|
||||||
verts2++;
|
|
||||||
}
|
}
|
||||||
else
|
GL_BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||||
{
|
glVertexPointer(3, GL_FLOAT, sizeof (vpos[0]), vpos);
|
||||||
glVertex3f (verts1->v[0], verts1->v[1], verts1->v[2]);
|
}
|
||||||
verts1++;
|
|
||||||
}
|
|
||||||
} while (--count);
|
|
||||||
|
|
||||||
glEnd ();
|
|
||||||
}
|
}
|
||||||
|
else if (paliashdr->posevertssize == 2)
|
||||||
|
{
|
||||||
|
md3XyzNormal_t *verts1 = (md3XyzNormal_t*)((byte *)paliashdr + paliashdr->vertexes) + lerpdata.pose1 * paliashdr->numverts_vbo;
|
||||||
|
md3XyzNormal_t *verts2 = (md3XyzNormal_t*)((byte *)paliashdr + paliashdr->vertexes) + lerpdata.pose2 * paliashdr->numverts_vbo;
|
||||||
|
|
||||||
|
if (iblend)
|
||||||
|
{
|
||||||
|
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||||
|
{
|
||||||
|
vpos[i][0] = verts1[i].xyz[0] * iblend + blend * verts2[i].xyz[0];
|
||||||
|
vpos[i][1] = verts1[i].xyz[1] * iblend + blend * verts2[i].xyz[1];
|
||||||
|
vpos[i][2] = verts1[i].xyz[2] * iblend + blend * verts2[i].xyz[2];
|
||||||
|
}
|
||||||
|
GL_BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||||
|
glVertexPointer(3, GL_FLOAT, sizeof (vpos[0]), vpos);
|
||||||
|
|
||||||
|
if (shading)
|
||||||
|
{
|
||||||
|
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||||
|
{
|
||||||
|
vec3_t n;
|
||||||
|
float dot;
|
||||||
|
// map the normal coordinates in [-1..1] to [-127..127] and store in an unsigned char.
|
||||||
|
// this introduces some error (less than 0.004), but the normals were very coarse
|
||||||
|
// to begin with
|
||||||
|
//this should be a table.
|
||||||
|
float lat = (float)verts2[i].latlong[0] * (2 * M_PI)*(1.0 / 255.0);
|
||||||
|
float lng = (float)verts2[i].latlong[1] * (2 * M_PI)*(1.0 / 255.0);
|
||||||
|
n[0] = blend * cos ( lng ) * sin ( lat );
|
||||||
|
n[1] = blend * sin ( lng ) * sin ( lat );
|
||||||
|
n[2] = blend * cos ( lat );
|
||||||
|
lat = (float)verts1[i].latlong[0] * (2 * M_PI)*(1.0 / 255.0);
|
||||||
|
lng = (float)verts1[i].latlong[1] * (2 * M_PI)*(1.0 / 255.0);
|
||||||
|
n[0] += iblend * cos ( lng ) * sin ( lat );
|
||||||
|
n[1] += iblend * sin ( lng ) * sin ( lat );
|
||||||
|
n[2] += iblend * cos ( lat );
|
||||||
|
dot = DotProduct(n, shadevector);
|
||||||
|
if (dot < 0.0) //bizzare maths guessed by mh
|
||||||
|
dot = 1.0 + dot * (13.0 / 44.0);
|
||||||
|
else
|
||||||
|
dot = 1.0 + dot;
|
||||||
|
vc[i][0] = dot * lightcolor[0];
|
||||||
|
vc[i][1] = dot * lightcolor[1];
|
||||||
|
vc[i][2] = dot * lightcolor[2];
|
||||||
|
vc[i][3] = entalpha;
|
||||||
|
}
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glColorPointer(4, GL_FLOAT, 0, vc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (shading)
|
||||||
|
{
|
||||||
|
for (i = 0; i < paliashdr->numverts_vbo; i++)
|
||||||
|
{
|
||||||
|
vec3_t n;
|
||||||
|
float dot;
|
||||||
|
// map the normal coordinates in [-1..1] to [-127..127] and store in an unsigned char.
|
||||||
|
// this introduces some error (less than 0.004), but the normals were very coarse
|
||||||
|
// to begin with
|
||||||
|
//this should be a table.
|
||||||
|
float lat = (float)verts2[i].latlong[0] * (2 * M_PI)*(1.0 / 255.0);
|
||||||
|
float lng = (float)verts2[i].latlong[1] * (2 * M_PI)*(1.0 / 255.0);
|
||||||
|
n[0] = cos ( lng ) * sin ( lat );
|
||||||
|
n[1] = sin ( lng ) * sin ( lat );
|
||||||
|
n[2] = cos ( lat );
|
||||||
|
dot = DotProduct(n, shadevector);
|
||||||
|
if (dot < 0.0) //bizzare maths guessed by mh
|
||||||
|
dot = 1.0 + dot * (13.0 / 44.0);
|
||||||
|
else
|
||||||
|
dot = 1.0 + dot;
|
||||||
|
vc[i][0] = dot * lightcolor[0];
|
||||||
|
vc[i][1] = dot * lightcolor[1];
|
||||||
|
vc[i][2] = dot * lightcolor[2];
|
||||||
|
vc[i][3] = entalpha;
|
||||||
|
}
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
GL_BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||||
|
glColorPointer(4, GL_FLOAT, 0, vc);
|
||||||
|
}
|
||||||
|
GL_BindBuffer (GL_ARRAY_BUFFER, currententity->model->meshvbo);
|
||||||
|
glVertexPointer(3, GL_SHORT, sizeof (meshxyz_md3_t), GLARB_GetXYZOffset_MD3 (paliashdr, lerpdata.pose2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set textures
|
||||||
|
GL_BindBuffer (GL_ARRAY_BUFFER, currententity->model->meshvbo);
|
||||||
|
if (mtexenabled)
|
||||||
|
{
|
||||||
|
GL_ClientActiveTextureFunc (GL_TEXTURE0);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||||
|
|
||||||
|
GL_ClientActiveTextureFunc (GL_TEXTURE1);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, currententity->model->meshvboptr+paliashdr->vbostofs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw
|
||||||
|
GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, currententity->model->meshindexesvbo);
|
||||||
|
glDrawElements (GL_TRIANGLES, paliashdr->numindexes, GL_UNSIGNED_SHORT, currententity->model->meshindexesvboptr + paliashdr->eboofs);
|
||||||
|
GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
GL_BindBuffer (GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
if (mtexenabled)
|
||||||
|
{
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
GL_ClientActiveTextureFunc (GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
|
||||||
rs_aliaspasses += paliashdr->numtris;
|
rs_aliaspasses += paliashdr->numtris;
|
||||||
}
|
}
|
||||||
|
@ -546,15 +671,18 @@ void R_SetupAliasLighting (entity_t *e)
|
||||||
int i;
|
int i;
|
||||||
int quantizedangle;
|
int quantizedangle;
|
||||||
float radiansangle;
|
float radiansangle;
|
||||||
|
float *origin = e->origin;
|
||||||
|
|
||||||
R_LightPoint (e->origin);
|
if (e->netstate.eflags & EFLAGS_VIEWMODEL)
|
||||||
|
origin = r_refdef.vieworg;
|
||||||
|
R_LightPoint (origin);
|
||||||
|
|
||||||
//add dlights
|
//add dlights
|
||||||
for (i=0 ; i<MAX_DLIGHTS ; i++)
|
for (i=0 ; i<MAX_DLIGHTS ; i++)
|
||||||
{
|
{
|
||||||
if (cl_dlights[i].die >= cl.time)
|
if (cl_dlights[i].die >= cl.time)
|
||||||
{
|
{
|
||||||
VectorSubtract (currententity->origin, cl_dlights[i].origin, dist);
|
VectorSubtract (origin, cl_dlights[i].origin, dist);
|
||||||
add = cl_dlights[i].radius - VectorLength(dist);
|
add = cl_dlights[i].radius - VectorLength(dist);
|
||||||
if (add > 0)
|
if (add > 0)
|
||||||
VectorMA (lightcolor, add, cl_dlights[i].color, lightcolor);
|
VectorMA (lightcolor, add, cl_dlights[i].color, lightcolor);
|
||||||
|
@ -574,7 +702,7 @@ void R_SetupAliasLighting (entity_t *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// minimum light value on players (8)
|
// minimum light value on players (8)
|
||||||
if (currententity > cl_entities && currententity <= cl_entities + cl.maxclients)
|
if (e > cl.entities && e <= cl.entities + cl.maxclients)
|
||||||
{
|
{
|
||||||
add = 24.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]);
|
add = 24.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]);
|
||||||
if (add > 0.0f)
|
if (add > 0.0f)
|
||||||
|
@ -615,6 +743,10 @@ void R_SetupAliasLighting (entity_t *e)
|
||||||
|
|
||||||
shadedots = r_avertexnormal_dots[quantizedangle];
|
shadedots = r_avertexnormal_dots[quantizedangle];
|
||||||
VectorScale (lightcolor, 1.0f / 200.0f, lightcolor);
|
VectorScale (lightcolor, 1.0f / 200.0f, lightcolor);
|
||||||
|
|
||||||
|
lightcolor[0] *= e->netstate.colormod[0] / 32.0;
|
||||||
|
lightcolor[1] *= e->netstate.colormod[1] / 32.0;
|
||||||
|
lightcolor[2] *= e->netstate.colormod[2] / 32.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -629,6 +761,7 @@ void R_DrawAliasModel (entity_t *e)
|
||||||
gltexture_t *tx, *fb;
|
gltexture_t *tx, *fb;
|
||||||
lerpdata_t lerpdata;
|
lerpdata_t lerpdata;
|
||||||
qboolean alphatest = !!(e->model->flags & MF_HOLEY);
|
qboolean alphatest = !!(e->model->flags & MF_HOLEY);
|
||||||
|
int surf;
|
||||||
|
|
||||||
//
|
//
|
||||||
// setup pose/lerp data -- do it first so we don't miss updates due to culling
|
// setup pose/lerp data -- do it first so we don't miss updates due to culling
|
||||||
|
@ -637,17 +770,30 @@ void R_DrawAliasModel (entity_t *e)
|
||||||
R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
|
R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
|
||||||
R_SetupEntityTransform (e, &lerpdata);
|
R_SetupEntityTransform (e, &lerpdata);
|
||||||
|
|
||||||
//
|
if (e->netstate.eflags & EFLAGS_VIEWMODEL)
|
||||||
// cull it
|
{
|
||||||
//
|
//transform it relative to the view, by rebuilding the modelview matrix without the view position.
|
||||||
if (R_CullModelForEntity(e))
|
glPushMatrix ();
|
||||||
return;
|
glLoadIdentity();
|
||||||
|
glRotatef (-90, 1, 0, 0); // put Z going up
|
||||||
|
glRotatef (90, 0, 0, 1); // put Z going up
|
||||||
|
|
||||||
//
|
glDepthRange (0, 0.3);
|
||||||
// transform it
|
}
|
||||||
//
|
else
|
||||||
glPushMatrix ();
|
{
|
||||||
R_RotateForEntity (lerpdata.origin, lerpdata.angles);
|
//
|
||||||
|
// cull it
|
||||||
|
//
|
||||||
|
if (R_CullModelForEntity(e))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//
|
||||||
|
// transform it
|
||||||
|
//
|
||||||
|
glPushMatrix ();
|
||||||
|
}
|
||||||
|
R_RotateForEntity (lerpdata.origin, lerpdata.angles, e->netstate.scale);
|
||||||
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
||||||
glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
|
glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
|
||||||
|
|
||||||
|
@ -682,110 +828,59 @@ void R_DrawAliasModel (entity_t *e)
|
||||||
//
|
//
|
||||||
// set up lighting
|
// set up lighting
|
||||||
//
|
//
|
||||||
rs_aliaspolys += paliashdr->numtris;
|
|
||||||
R_SetupAliasLighting (e);
|
R_SetupAliasLighting (e);
|
||||||
|
|
||||||
//
|
for(surf=0;;surf++)
|
||||||
// set up textures
|
|
||||||
//
|
|
||||||
GL_DisableMultitexture();
|
|
||||||
anim = (int)(cl.time*10) & 3;
|
|
||||||
skinnum = e->skinnum;
|
|
||||||
if ((skinnum >= paliashdr->numskins) || (skinnum < 0))
|
|
||||||
{
|
{
|
||||||
Con_DPrintf ("R_DrawAliasModel: no such skin # %d for '%s'\n", skinnum, e->model->name);
|
rs_aliaspolys += paliashdr->numtris;
|
||||||
// ericw -- display skin 0 for winquake compatibility
|
|
||||||
skinnum = 0;
|
|
||||||
}
|
|
||||||
tx = paliashdr->gltextures[skinnum][anim];
|
|
||||||
fb = paliashdr->fbtextures[skinnum][anim];
|
|
||||||
if (e->colormap != vid.colormap && !gl_nocolors.value)
|
|
||||||
{
|
|
||||||
i = e - cl_entities;
|
|
||||||
if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
|
|
||||||
tx = playertextures[i - 1];
|
|
||||||
}
|
|
||||||
if (!gl_fullbrights.value)
|
|
||||||
fb = NULL;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// draw it
|
// set up textures
|
||||||
//
|
//
|
||||||
if (r_drawflat_cheatsafe)
|
GL_DisableMultitexture();
|
||||||
{
|
anim = (int)(cl.time*10) & 3;
|
||||||
glDisable (GL_TEXTURE_2D);
|
skinnum = e->skinnum;
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
if ((skinnum >= paliashdr->numskins) || (skinnum < 0))
|
||||||
glEnable (GL_TEXTURE_2D);
|
|
||||||
srand((int) (cl.time * 1000)); //restore randomness
|
|
||||||
}
|
|
||||||
else if (r_fullbright_cheatsafe)
|
|
||||||
{
|
|
||||||
GL_Bind (tx);
|
|
||||||
shading = false;
|
|
||||||
glColor4f(1,1,1,entalpha);
|
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
||||||
if (fb)
|
|
||||||
{
|
{
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
Con_DPrintf ("R_DrawAliasModel: no such skin # %d for '%s'\n", skinnum, e->model->name);
|
||||||
GL_Bind(fb);
|
// ericw -- display skin 0 for winquake compatibility
|
||||||
glEnable(GL_BLEND);
|
skinnum = 0;
|
||||||
glBlendFunc (GL_ONE, GL_ONE);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
glColor3f(entalpha,entalpha,entalpha);
|
|
||||||
Fog_StartAdditive ();
|
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
||||||
Fog_StopAdditive ();
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
}
|
}
|
||||||
}
|
if (paliashdr->numskins <= 0)
|
||||||
else if (r_lightmap_cheatsafe)
|
{
|
||||||
{
|
tx = NULL; // NULL will give the checkerboard texture
|
||||||
glDisable (GL_TEXTURE_2D);
|
fb = NULL;
|
||||||
shading = false;
|
}
|
||||||
glColor3f(1,1,1);
|
else
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
{
|
||||||
glEnable (GL_TEXTURE_2D);
|
tx = paliashdr->gltextures[skinnum][anim];
|
||||||
}
|
fb = paliashdr->fbtextures[skinnum][anim];
|
||||||
// call fast path if possible. if the shader compliation failed for some reason,
|
}
|
||||||
// r_alias_program will be 0.
|
if (e->colormap != vid.colormap && !gl_nocolors.value)
|
||||||
else if (r_alias_program != 0)
|
{
|
||||||
{
|
i = e - cl.entities;
|
||||||
GL_DrawAliasFrame_GLSL (paliashdr, lerpdata, tx, fb);
|
if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
|
||||||
}
|
tx = playertextures[i - 1];
|
||||||
else if (overbright)
|
}
|
||||||
{
|
if (!gl_fullbrights.value)
|
||||||
if (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && fb) //case 1: everything in one pass
|
fb = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
// draw it
|
||||||
|
//
|
||||||
|
if (r_drawflat_cheatsafe)
|
||||||
|
{
|
||||||
|
glDisable (GL_TEXTURE_2D);
|
||||||
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
glEnable (GL_TEXTURE_2D);
|
||||||
|
srand((int) (cl.time * 1000)); //restore randomness
|
||||||
|
}
|
||||||
|
else if (r_fullbright_cheatsafe)
|
||||||
{
|
{
|
||||||
GL_Bind (tx);
|
GL_Bind (tx);
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
shading = false;
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
|
glColor4f(1,1,1,entalpha);
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
|
|
||||||
GL_EnableMultitexture(); // selects TEXTURE1
|
|
||||||
GL_Bind (fb);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
glDisable(GL_BLEND);
|
|
||||||
GL_DisableMultitexture();
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
}
|
|
||||||
else if (gl_texture_env_combine) //case 2: overbright in one pass, then fullbright pass
|
|
||||||
{
|
|
||||||
// first pass
|
|
||||||
GL_Bind(tx);
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
|
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
// second pass
|
|
||||||
if (fb)
|
if (fb)
|
||||||
{
|
{
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
@ -793,7 +888,6 @@ void R_DrawAliasModel (entity_t *e)
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc (GL_ONE, GL_ONE);
|
glBlendFunc (GL_ONE, GL_ONE);
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
shading = false;
|
|
||||||
glColor3f(entalpha,entalpha,entalpha);
|
glColor3f(entalpha,entalpha,entalpha);
|
||||||
Fog_StartAdditive ();
|
Fog_StartAdditive ();
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
@ -801,85 +895,152 @@ void R_DrawAliasModel (entity_t *e)
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //case 3: overbright in two passes, then fullbright pass
|
else if (r_lightmap_cheatsafe)
|
||||||
{
|
{
|
||||||
// first pass
|
glDisable (GL_TEXTURE_2D);
|
||||||
GL_Bind(tx);
|
shading = false;
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
glColor3f(1,1,1);
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
// second pass -- additive with black fog, to double the object colors but not the fog color
|
glEnable (GL_TEXTURE_2D);
|
||||||
glEnable(GL_BLEND);
|
}
|
||||||
glBlendFunc (GL_ONE, GL_ONE);
|
// call fast path if possible. if the shader compliation failed for some reason,
|
||||||
glDepthMask(GL_FALSE);
|
// r_alias_program will be 0.
|
||||||
Fog_StartAdditive ();
|
else if (r_alias_program != 0)
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
{
|
||||||
Fog_StopAdditive ();
|
GL_DrawAliasFrame_GLSL (paliashdr, lerpdata, tx, fb);
|
||||||
glDepthMask(GL_TRUE);
|
}
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
else if (overbright)
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
{
|
||||||
glDisable(GL_BLEND);
|
if (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && fb) //case 1: everything in one pass
|
||||||
// third pass
|
|
||||||
if (fb)
|
|
||||||
{
|
{
|
||||||
|
GL_Bind (tx);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
|
||||||
|
GL_EnableMultitexture(); // selects TEXTURE1
|
||||||
|
GL_Bind (fb);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
|
||||||
|
// glEnable(GL_BLEND);
|
||||||
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
// glDisable(GL_BLEND);
|
||||||
|
GL_DisableMultitexture();
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
}
|
||||||
|
else if (gl_texture_env_combine) //case 2: overbright in one pass, then fullbright pass
|
||||||
|
{
|
||||||
|
// first pass
|
||||||
|
GL_Bind(tx);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
|
||||||
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
// second pass
|
||||||
|
if (fb)
|
||||||
|
{
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
GL_Bind(fb);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc (GL_ONE, GL_ONE);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
shading = false;
|
||||||
|
glColor3f(entalpha,entalpha,entalpha);
|
||||||
|
Fog_StartAdditive ();
|
||||||
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
Fog_StopAdditive ();
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //case 3: overbright in two passes, then fullbright pass
|
||||||
|
{
|
||||||
|
// first pass
|
||||||
|
GL_Bind(tx);
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
GL_Bind(fb);
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
// second pass -- additive with black fog, to double the object colors but not the fog color
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc (GL_ONE, GL_ONE);
|
glBlendFunc (GL_ONE, GL_ONE);
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
shading = false;
|
|
||||||
glColor3f(entalpha,entalpha,entalpha);
|
|
||||||
Fog_StartAdditive ();
|
Fog_StartAdditive ();
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
Fog_StopAdditive ();
|
Fog_StopAdditive ();
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
// third pass
|
||||||
|
if (fb)
|
||||||
|
{
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
GL_Bind(fb);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc (GL_ONE, GL_ONE);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
shading = false;
|
||||||
|
glColor3f(entalpha,entalpha,entalpha);
|
||||||
|
Fog_StartAdditive ();
|
||||||
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
Fog_StopAdditive ();
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (gl_mtexable && gl_texture_env_add && fb) //case 4: fullbright mask using multitexture
|
||||||
|
{
|
||||||
|
GL_DisableMultitexture(); // selects TEXTURE0
|
||||||
|
GL_Bind (tx);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
GL_EnableMultitexture(); // selects TEXTURE1
|
||||||
|
GL_Bind (fb);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
GL_DisableMultitexture();
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
}
|
}
|
||||||
}
|
else //case 5: fullbright mask without multitexture
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (gl_mtexable && gl_texture_env_add && fb) //case 4: fullbright mask using multitexture
|
|
||||||
{
|
|
||||||
GL_DisableMultitexture(); // selects TEXTURE0
|
|
||||||
GL_Bind (tx);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
||||||
GL_EnableMultitexture(); // selects TEXTURE1
|
|
||||||
GL_Bind (fb);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
GL_DisableMultitexture();
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
}
|
|
||||||
else //case 5: fullbright mask without multitexture
|
|
||||||
{
|
|
||||||
// first pass
|
|
||||||
GL_Bind(tx);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
||||||
// second pass
|
|
||||||
if (fb)
|
|
||||||
{
|
{
|
||||||
GL_Bind(fb);
|
// first pass
|
||||||
glEnable(GL_BLEND);
|
GL_Bind(tx);
|
||||||
glBlendFunc (GL_ONE, GL_ONE);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
shading = false;
|
|
||||||
glColor3f(entalpha,entalpha,entalpha);
|
|
||||||
Fog_StartAdditive ();
|
|
||||||
GL_DrawAliasFrame (paliashdr, lerpdata);
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
Fog_StopAdditive ();
|
// second pass
|
||||||
glDepthMask(GL_TRUE);
|
if (fb)
|
||||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
{
|
||||||
glDisable(GL_BLEND);
|
GL_Bind(fb);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc (GL_ONE, GL_ONE);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
shading = false;
|
||||||
|
glColor3f(entalpha,entalpha,entalpha);
|
||||||
|
Fog_StartAdditive ();
|
||||||
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
||||||
|
Fog_StopAdditive ();
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!paliashdr->nextsurface)
|
||||||
|
break;
|
||||||
|
paliashdr = (aliashdr_t*)((byte*)paliashdr + paliashdr->nextsurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
@ -891,6 +1052,8 @@ cleanup:
|
||||||
if (alphatest)
|
if (alphatest)
|
||||||
glDisable (GL_ALPHA_TEST);
|
glDisable (GL_ALPHA_TEST);
|
||||||
glColor3f(1,1,1);
|
glColor3f(1,1,1);
|
||||||
|
if (e->netstate.eflags & EFLAGS_VIEWMODEL)
|
||||||
|
glDepthRange (0, 1);
|
||||||
glPopMatrix ();
|
glPopMatrix ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -921,7 +1084,7 @@ void GL_DrawAliasShadow (entity_t *e)
|
||||||
if (R_CullModelForEntity(e))
|
if (R_CullModelForEntity(e))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (e == &cl.viewent || e->model->flags & MOD_NOSHADOW)
|
if (e == &cl.viewent || e->effects & EF_NOSHADOW || e->model->flags & MOD_NOSHADOW)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
entalpha = ENTALPHA_DECODE(e->alpha);
|
entalpha = ENTALPHA_DECODE(e->alpha);
|
||||||
|
@ -979,7 +1142,7 @@ void R_DrawAliasModel_ShowTris (entity_t *e)
|
||||||
R_SetupEntityTransform (e, &lerpdata);
|
R_SetupEntityTransform (e, &lerpdata);
|
||||||
|
|
||||||
glPushMatrix ();
|
glPushMatrix ();
|
||||||
R_RotateForEntity (lerpdata.origin,lerpdata.angles);
|
R_RotateForEntity (lerpdata.origin,lerpdata.angles, e->netstate.scale);
|
||||||
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
||||||
glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
|
glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
|
||||||
|
|
||||||
|
|
|
@ -549,7 +549,7 @@ void R_DrawBrushModel (entity_t *e)
|
||||||
e->origin[1] -= DIST_EPSILON;
|
e->origin[1] -= DIST_EPSILON;
|
||||||
e->origin[2] -= DIST_EPSILON;
|
e->origin[2] -= DIST_EPSILON;
|
||||||
}
|
}
|
||||||
R_RotateForEntity (e->origin, e->angles);
|
R_RotateForEntity (e->origin, e->angles, e->netstate.scale);
|
||||||
if (gl_zfix.value)
|
if (gl_zfix.value)
|
||||||
{
|
{
|
||||||
e->origin[0] += DIST_EPSILON;
|
e->origin[0] += DIST_EPSILON;
|
||||||
|
@ -614,7 +614,7 @@ void R_DrawBrushModel_ShowTris (entity_t *e)
|
||||||
|
|
||||||
glPushMatrix ();
|
glPushMatrix ();
|
||||||
e->angles[0] = -e->angles[0]; // stupid quake bug
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
||||||
R_RotateForEntity (e->origin, e->angles);
|
R_RotateForEntity (e->origin, e->angles, e->netstate.scale);
|
||||||
e->angles[0] = -e->angles[0]; // stupid quake bug
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -652,7 +652,7 @@ R_RenderDynamicLightmaps
|
||||||
called during rendering
|
called during rendering
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
void R_RenderDynamicLightmaps (msurface_t *fa)
|
void R_RenderDynamicLightmaps (qmodel_t *model, msurface_t *fa)
|
||||||
{
|
{
|
||||||
byte *base;
|
byte *base;
|
||||||
int maps;
|
int maps;
|
||||||
|
@ -698,7 +698,7 @@ dynamic:
|
||||||
theRect->h = (fa->light_t-theRect->t)+tmax;
|
theRect->h = (fa->light_t-theRect->t)+tmax;
|
||||||
base = lm->data;
|
base = lm->data;
|
||||||
base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
|
base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
|
||||||
R_BuildLightMap (fa, base, LMBLOCK_WIDTH*lightmap_bytes);
|
R_BuildLightMap (model, fa, base, LMBLOCK_WIDTH*lightmap_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -777,7 +777,7 @@ int nColinElim;
|
||||||
GL_CreateSurfaceLightmap
|
GL_CreateSurfaceLightmap
|
||||||
========================
|
========================
|
||||||
*/
|
*/
|
||||||
void GL_CreateSurfaceLightmap (msurface_t *surf)
|
void GL_CreateSurfaceLightmap (qmodel_t *model, msurface_t *surf)
|
||||||
{
|
{
|
||||||
int smax, tmax;
|
int smax, tmax;
|
||||||
byte *base;
|
byte *base;
|
||||||
|
@ -788,7 +788,7 @@ void GL_CreateSurfaceLightmap (msurface_t *surf)
|
||||||
surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
|
surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
|
||||||
base = lightmap[surf->lightmaptexturenum].data;
|
base = lightmap[surf->lightmaptexturenum].data;
|
||||||
base += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * lightmap_bytes;
|
base += (surf->light_t * LMBLOCK_WIDTH + surf->light_s) * lightmap_bytes;
|
||||||
R_BuildLightMap (surf, base, LMBLOCK_WIDTH*lightmap_bytes);
|
R_BuildLightMap (model, surf, base, LMBLOCK_WIDTH*lightmap_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -917,7 +917,7 @@ void GL_BuildLightmaps (void)
|
||||||
//johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags
|
//johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags
|
||||||
if (m->surfaces[i].flags & SURF_DRAWTILED)
|
if (m->surfaces[i].flags & SURF_DRAWTILED)
|
||||||
continue;
|
continue;
|
||||||
GL_CreateSurfaceLightmap (m->surfaces + i);
|
GL_CreateSurfaceLightmap (m, m->surfaces + i);
|
||||||
BuildSurfaceDisplayList (m->surfaces + i);
|
BuildSurfaceDisplayList (m->surfaces + i);
|
||||||
//johnfitz
|
//johnfitz
|
||||||
}
|
}
|
||||||
|
@ -1130,7 +1130,7 @@ R_BuildLightMap -- johnfitz -- revised for lit support via lordhavoc
|
||||||
Combine and scale multiple lightmaps into the 8.8 format in blocklights
|
Combine and scale multiple lightmaps into the 8.8 format in blocklights
|
||||||
===============
|
===============
|
||||||
*/
|
*/
|
||||||
void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
|
void R_BuildLightMap (qmodel_t *model, msurface_t *surf, byte *dest, int stride)
|
||||||
{
|
{
|
||||||
int smax, tmax;
|
int smax, tmax;
|
||||||
int r,g,b;
|
int r,g,b;
|
||||||
|
@ -1147,7 +1147,7 @@ void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
|
||||||
size = smax*tmax;
|
size = smax*tmax;
|
||||||
lightmap = surf->samples;
|
lightmap = surf->samples;
|
||||||
|
|
||||||
if (cl.worldmodel->lightdata)
|
if (model->lightdata)
|
||||||
{
|
{
|
||||||
// clear to no light
|
// clear to no light
|
||||||
memset (&blocklights[0], 0, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc
|
memset (&blocklights[0], 0, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc
|
||||||
|
@ -1310,7 +1310,7 @@ void R_RebuildAllLightmaps (void)
|
||||||
continue;
|
continue;
|
||||||
base = lightmap[fa->lightmaptexturenum].data;
|
base = lightmap[fa->lightmaptexturenum].data;
|
||||||
base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
|
base += fa->light_t * LMBLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
|
||||||
R_BuildLightMap (fa, base, LMBLOCK_WIDTH*lightmap_bytes);
|
R_BuildLightMap (mod, fa, base, LMBLOCK_WIDTH*lightmap_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -337,9 +337,19 @@ void R_ParseParticleEffect (void)
|
||||||
color = MSG_ReadByte ();
|
color = MSG_ReadByte ();
|
||||||
|
|
||||||
if (msgcount == 255)
|
if (msgcount == 255)
|
||||||
count = 1024;
|
{
|
||||||
|
if (!PScript_RunParticleEffectTypeString(org, dir, 1, "te_explosion"))
|
||||||
|
count = 0;
|
||||||
|
else
|
||||||
|
count = 1024;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
count = msgcount;
|
{
|
||||||
|
if (!PScript_RunParticleEffect(org, dir, color, msgcount))
|
||||||
|
count = 0;
|
||||||
|
else
|
||||||
|
count = msgcount;
|
||||||
|
}
|
||||||
|
|
||||||
R_RunParticleEffect (org, dir, color, count);
|
R_RunParticleEffect (org, dir, color, count);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -86,6 +86,7 @@ void R_DrawSpriteModel (entity_t *e)
|
||||||
mspriteframe_t *frame;
|
mspriteframe_t *frame;
|
||||||
float *s_up, *s_right;
|
float *s_up, *s_right;
|
||||||
float angle, sr, cr;
|
float angle, sr, cr;
|
||||||
|
float scale;
|
||||||
|
|
||||||
//TODO: frustum cull it?
|
//TODO: frustum cull it?
|
||||||
|
|
||||||
|
@ -144,7 +145,12 @@ void R_DrawSpriteModel (entity_t *e)
|
||||||
if (psprite->type == SPR_ORIENTED)
|
if (psprite->type == SPR_ORIENTED)
|
||||||
GL_PolygonOffset (OFFSET_DECAL);
|
GL_PolygonOffset (OFFSET_DECAL);
|
||||||
|
|
||||||
glColor3f (1,1,1);
|
if (e->netstate.scale != 16)
|
||||||
|
scale = e->netstate.scale/16.0;
|
||||||
|
else
|
||||||
|
scale = 1;
|
||||||
|
|
||||||
|
glColor3f (e->netstate.colormod[0]/32.0,e->netstate.colormod[0]/32.0,e->netstate.colormod[0]/32.0);
|
||||||
|
|
||||||
GL_DisableMultitexture();
|
GL_DisableMultitexture();
|
||||||
|
|
||||||
|
@ -154,28 +160,30 @@ void R_DrawSpriteModel (entity_t *e)
|
||||||
glBegin (GL_TRIANGLE_FAN); //was GL_QUADS, but changed to support r_showtris
|
glBegin (GL_TRIANGLE_FAN); //was GL_QUADS, but changed to support r_showtris
|
||||||
|
|
||||||
glTexCoord2f (0, frame->tmax);
|
glTexCoord2f (0, frame->tmax);
|
||||||
VectorMA (e->origin, frame->down, s_up, point);
|
VectorMA (e->origin, frame->down*scale, s_up, point);
|
||||||
VectorMA (point, frame->left, s_right, point);
|
VectorMA (point, frame->left*scale, s_right, point);
|
||||||
glVertex3fv (point);
|
glVertex3fv (point);
|
||||||
|
|
||||||
glTexCoord2f (0, 0);
|
glTexCoord2f (0, 0);
|
||||||
VectorMA (e->origin, frame->up, s_up, point);
|
VectorMA (e->origin, frame->up*scale, s_up, point);
|
||||||
VectorMA (point, frame->left, s_right, point);
|
VectorMA (point, frame->left*scale, s_right, point);
|
||||||
glVertex3fv (point);
|
glVertex3fv (point);
|
||||||
|
|
||||||
glTexCoord2f (frame->smax, 0);
|
glTexCoord2f (frame->smax, 0);
|
||||||
VectorMA (e->origin, frame->up, s_up, point);
|
VectorMA (e->origin, frame->up*scale, s_up, point);
|
||||||
VectorMA (point, frame->right, s_right, point);
|
VectorMA (point, frame->right*scale, s_right, point);
|
||||||
glVertex3fv (point);
|
glVertex3fv (point);
|
||||||
|
|
||||||
glTexCoord2f (frame->smax, frame->tmax);
|
glTexCoord2f (frame->smax, frame->tmax);
|
||||||
VectorMA (e->origin, frame->down, s_up, point);
|
VectorMA (e->origin, frame->down*scale, s_up, point);
|
||||||
VectorMA (point, frame->right, s_right, point);
|
VectorMA (point, frame->right*scale, s_right, point);
|
||||||
glVertex3fv (point);
|
glVertex3fv (point);
|
||||||
|
|
||||||
glEnd ();
|
glEnd ();
|
||||||
glDisable (GL_ALPHA_TEST);
|
glDisable (GL_ALPHA_TEST);
|
||||||
|
|
||||||
|
glColor3f (1, 1, 1);
|
||||||
|
|
||||||
//johnfitz: offset decals
|
//johnfitz: offset decals
|
||||||
if (psprite->type == SPR_ORIENTED)
|
if (psprite->type == SPR_ORIENTED)
|
||||||
GL_PolygonOffset (OFFSET_NONE);
|
GL_PolygonOffset (OFFSET_NONE);
|
||||||
|
|
|
@ -81,6 +81,7 @@ void R_MarkSurfaces (void)
|
||||||
mnode_t *node;
|
mnode_t *node;
|
||||||
msurface_t *surf, **mark;
|
msurface_t *surf, **mark;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
unsigned int k;
|
||||||
qboolean nearwaterportal;
|
qboolean nearwaterportal;
|
||||||
|
|
||||||
// clear lightmap chains
|
// clear lightmap chains
|
||||||
|
@ -146,7 +147,7 @@ void R_MarkSurfaces (void)
|
||||||
//becuase his tool doesn't actually remove the surfaces from the bsp surfaces lump
|
//becuase his tool doesn't actually remove the surfaces from the bsp surfaces lump
|
||||||
//nor does it remove references to them in each leaf's marksurfaces list
|
//nor does it remove references to them in each leaf's marksurfaces list
|
||||||
for (i=0, node = cl.worldmodel->nodes ; i<cl.worldmodel->numnodes ; i++, node++)
|
for (i=0, node = cl.worldmodel->nodes ; i<cl.worldmodel->numnodes ; i++, node++)
|
||||||
for (j=0, surf=&cl.worldmodel->surfaces[node->firstsurface] ; j<node->numsurfaces ; j++, surf++)
|
for (k=0, surf=&cl.worldmodel->surfaces[node->firstsurface] ; k<node->numsurfaces ; k++, surf++)
|
||||||
if (surf->visframe == r_visframecount)
|
if (surf->visframe == r_visframecount)
|
||||||
{
|
{
|
||||||
R_ChainSurface(surf, chain_world);
|
R_ChainSurface(surf, chain_world);
|
||||||
|
@ -261,7 +262,7 @@ void R_BuildLightmapChains (qmodel_t *model, texchain_t chain)
|
||||||
|
|
||||||
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
||||||
if (!s->culled)
|
if (!s->culled)
|
||||||
R_RenderDynamicLightmaps (s);
|
R_RenderDynamicLightmaps (model, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ typedef struct entity_s
|
||||||
int update_type;
|
int update_type;
|
||||||
|
|
||||||
entity_state_t baseline; // to fill in defaults in updates
|
entity_state_t baseline; // to fill in defaults in updates
|
||||||
|
entity_state_t netstate; // the latest network state
|
||||||
|
|
||||||
double msgtime; // time of last update
|
double msgtime; // time of last update
|
||||||
vec3_t msg_origins[2]; // last two updates (0 is newest)
|
vec3_t msg_origins[2]; // last two updates (0 is newest)
|
||||||
|
@ -91,6 +92,9 @@ typedef struct entity_s
|
||||||
vec3_t currentorigin; //johnfitz -- transform lerping
|
vec3_t currentorigin; //johnfitz -- transform lerping
|
||||||
vec3_t previousangles; //johnfitz -- transform lerping
|
vec3_t previousangles; //johnfitz -- transform lerping
|
||||||
vec3_t currentangles; //johnfitz -- transform lerping
|
vec3_t currentangles; //johnfitz -- transform lerping
|
||||||
|
|
||||||
|
struct trailstate_s *trailstate; //spike -- managed by the particle system, so we don't loose our position and spawn the wrong number of particles, and we can track beams etc
|
||||||
|
struct trailstate_s *emitstate; //spike -- for effects which are not so static.
|
||||||
} entity_t;
|
} entity_t;
|
||||||
|
|
||||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||||
|
|
165
Quake/sbar.c
165
Quake/sbar.c
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
|
|
||||||
|
extern qboolean premul_hud;
|
||||||
int sb_updates; // if >= vid.numpages, no update needed
|
int sb_updates; // if >= vid.numpages, no update needed
|
||||||
|
|
||||||
#define STAT_MINUS 10 // num frame for '-' stats digit
|
#define STAT_MINUS 10 // num frame for '-' stats digit
|
||||||
|
@ -63,6 +64,11 @@ int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_B
|
||||||
//MED 01/04/97 added hipnotic items array
|
//MED 01/04/97 added hipnotic items array
|
||||||
qpic_t *hsb_items[2];
|
qpic_t *hsb_items[2];
|
||||||
|
|
||||||
|
//spike -- fix -game hipnotic by autodetecting hud types. the fte protocols will deal with the networking issue, other than demos, anyway
|
||||||
|
static int hudtype;
|
||||||
|
#define hipnotic (hudtype==1)
|
||||||
|
#define rogue (hudtype==2)
|
||||||
|
|
||||||
void Sbar_MiniDeathmatchOverlay (void);
|
void Sbar_MiniDeathmatchOverlay (void);
|
||||||
void Sbar_DeathmatchOverlay (void);
|
void Sbar_DeathmatchOverlay (void);
|
||||||
void M_DrawPic (int x, int y, qpic_t *pic);
|
void M_DrawPic (int x, int y, qpic_t *pic);
|
||||||
|
@ -105,6 +111,21 @@ void Sbar_Changed (void)
|
||||||
sb_updates = 0; // update next frame
|
sb_updates = 0; // update next frame
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qpic_t *Sbar_CheckPicFromWad (const char *name)
|
||||||
|
{
|
||||||
|
extern qpic_t *pic_nul;
|
||||||
|
qpic_t *r;
|
||||||
|
if (!hudtype)
|
||||||
|
return pic_nul; //one already failed, don't waste cpu
|
||||||
|
if (!W_GetLumpinfo(name))
|
||||||
|
r = pic_nul;
|
||||||
|
else
|
||||||
|
r = Draw_PicFromWad(name);
|
||||||
|
if (r == pic_nul)
|
||||||
|
hudtype = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
Sbar_LoadPics -- johnfitz -- load all the sbar pics
|
Sbar_LoadPics -- johnfitz -- load all the sbar pics
|
||||||
|
@ -194,55 +215,59 @@ void Sbar_LoadPics (void)
|
||||||
sb_ibar = Draw_PicFromWad ("ibar");
|
sb_ibar = Draw_PicFromWad ("ibar");
|
||||||
sb_scorebar = Draw_PicFromWad ("scorebar");
|
sb_scorebar = Draw_PicFromWad ("scorebar");
|
||||||
|
|
||||||
//MED 01/04/97 added new hipnotic weapons
|
hudtype = 0;
|
||||||
if (hipnotic)
|
|
||||||
{
|
|
||||||
hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser");
|
|
||||||
hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir");
|
|
||||||
hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox");
|
|
||||||
hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren");
|
|
||||||
hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox");
|
|
||||||
|
|
||||||
hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser");
|
//MED 01/04/97 added new hipnotic weapons
|
||||||
hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir");
|
if (!hudtype)
|
||||||
hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox");
|
{
|
||||||
hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren");
|
hudtype = 1;
|
||||||
hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox");
|
hsb_weapons[0][0] = Sbar_CheckPicFromWad ("inv_laser");
|
||||||
|
hsb_weapons[0][1] = Sbar_CheckPicFromWad ("inv_mjolnir");
|
||||||
|
hsb_weapons[0][2] = Sbar_CheckPicFromWad ("inv_gren_prox");
|
||||||
|
hsb_weapons[0][3] = Sbar_CheckPicFromWad ("inv_prox_gren");
|
||||||
|
hsb_weapons[0][4] = Sbar_CheckPicFromWad ("inv_prox");
|
||||||
|
|
||||||
|
hsb_weapons[1][0] = Sbar_CheckPicFromWad ("inv2_laser");
|
||||||
|
hsb_weapons[1][1] = Sbar_CheckPicFromWad ("inv2_mjolnir");
|
||||||
|
hsb_weapons[1][2] = Sbar_CheckPicFromWad ("inv2_gren_prox");
|
||||||
|
hsb_weapons[1][3] = Sbar_CheckPicFromWad ("inv2_prox_gren");
|
||||||
|
hsb_weapons[1][4] = Sbar_CheckPicFromWad ("inv2_prox");
|
||||||
|
|
||||||
for (i = 0; i < 5; i++)
|
for (i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1));
|
hsb_weapons[2+i][0] = Sbar_CheckPicFromWad (va("inva%i_laser",i+1));
|
||||||
hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1));
|
hsb_weapons[2+i][1] = Sbar_CheckPicFromWad (va("inva%i_mjolnir",i+1));
|
||||||
hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1));
|
hsb_weapons[2+i][2] = Sbar_CheckPicFromWad (va("inva%i_gren_prox",i+1));
|
||||||
hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1));
|
hsb_weapons[2+i][3] = Sbar_CheckPicFromWad (va("inva%i_prox_gren",i+1));
|
||||||
hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1));
|
hsb_weapons[2+i][4] = Sbar_CheckPicFromWad (va("inva%i_prox",i+1));
|
||||||
}
|
}
|
||||||
|
|
||||||
hsb_items[0] = Draw_PicFromWad ("sb_wsuit");
|
hsb_items[0] = Sbar_CheckPicFromWad ("sb_wsuit");
|
||||||
hsb_items[1] = Draw_PicFromWad ("sb_eshld");
|
hsb_items[1] = Sbar_CheckPicFromWad ("sb_eshld");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rogue)
|
if (!hudtype)
|
||||||
{
|
{
|
||||||
rsb_invbar[0] = Draw_PicFromWad ("r_invbar1");
|
hudtype = 2;
|
||||||
rsb_invbar[1] = Draw_PicFromWad ("r_invbar2");
|
rsb_invbar[0] = Sbar_CheckPicFromWad ("r_invbar1");
|
||||||
|
rsb_invbar[1] = Sbar_CheckPicFromWad ("r_invbar2");
|
||||||
|
|
||||||
rsb_weapons[0] = Draw_PicFromWad ("r_lava");
|
rsb_weapons[0] = Sbar_CheckPicFromWad ("r_lava");
|
||||||
rsb_weapons[1] = Draw_PicFromWad ("r_superlava");
|
rsb_weapons[1] = Sbar_CheckPicFromWad ("r_superlava");
|
||||||
rsb_weapons[2] = Draw_PicFromWad ("r_gren");
|
rsb_weapons[2] = Sbar_CheckPicFromWad ("r_gren");
|
||||||
rsb_weapons[3] = Draw_PicFromWad ("r_multirock");
|
rsb_weapons[3] = Sbar_CheckPicFromWad ("r_multirock");
|
||||||
rsb_weapons[4] = Draw_PicFromWad ("r_plasma");
|
rsb_weapons[4] = Sbar_CheckPicFromWad ("r_plasma");
|
||||||
|
|
||||||
rsb_items[0] = Draw_PicFromWad ("r_shield1");
|
rsb_items[0] = Sbar_CheckPicFromWad ("r_shield1");
|
||||||
rsb_items[1] = Draw_PicFromWad ("r_agrav1");
|
rsb_items[1] = Sbar_CheckPicFromWad ("r_agrav1");
|
||||||
|
|
||||||
// PGM 01/19/97 - team color border
|
// PGM 01/19/97 - team color border
|
||||||
rsb_teambord = Draw_PicFromWad ("r_teambord");
|
rsb_teambord = Sbar_CheckPicFromWad ("r_teambord");
|
||||||
// PGM 01/19/97 - team color border
|
// PGM 01/19/97 - team color border
|
||||||
|
|
||||||
rsb_ammo[0] = Draw_PicFromWad ("r_ammolava");
|
rsb_ammo[0] = Sbar_CheckPicFromWad ("r_ammolava");
|
||||||
rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti");
|
rsb_ammo[1] = Sbar_CheckPicFromWad ("r_ammomulti");
|
||||||
rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma");
|
rsb_ammo[2] = Sbar_CheckPicFromWad ("r_ammoplasma");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,13 +306,22 @@ Sbar_DrawPicAlpha -- johnfitz
|
||||||
*/
|
*/
|
||||||
void Sbar_DrawPicAlpha (int x, int y, qpic_t *pic, float alpha)
|
void Sbar_DrawPicAlpha (int x, int y, qpic_t *pic, float alpha)
|
||||||
{
|
{
|
||||||
glDisable (GL_ALPHA_TEST);
|
if (premul_hud)
|
||||||
glEnable (GL_BLEND);
|
{
|
||||||
glColor4f(1,1,1,alpha);
|
glColor4f(alpha,alpha,alpha,alpha);
|
||||||
Draw_Pic (x, y + 24, pic);
|
Draw_Pic (x, y + 24, pic);
|
||||||
glColor4f(1,1,1,1); // ericw -- changed from glColor3f to work around intel 855 bug with "r_oldwater 0" and "scr_sbaralpha 0"
|
glColor4f(1,1,1,1);
|
||||||
glDisable (GL_BLEND);
|
}
|
||||||
glEnable (GL_ALPHA_TEST);
|
else
|
||||||
|
{
|
||||||
|
glDisable (GL_ALPHA_TEST);
|
||||||
|
glEnable (GL_BLEND);
|
||||||
|
glColor4f(1,1,1,alpha);
|
||||||
|
Draw_Pic (x, y + 24, pic);
|
||||||
|
glColor4f(1,1,1,1); // ericw -- changed from glColor3f to work around intel 855 bug with "r_oldwater 0" and "scr_sbaralpha 0"
|
||||||
|
glDisable (GL_BLEND);
|
||||||
|
glEnable (GL_ALPHA_TEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -918,6 +952,35 @@ void Sbar_DrawFace (void)
|
||||||
Sbar_DrawPic (112, 0, sb_faces[f][anim]);
|
Sbar_DrawPic (112, 0, sb_faces[f][anim]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Sbar_Voice(int y)
|
||||||
|
{
|
||||||
|
cvar_t snd_voip_showmeter;
|
||||||
|
int loudness;
|
||||||
|
snd_voip_showmeter.value = 1;
|
||||||
|
if (!snd_voip_showmeter.value)
|
||||||
|
return;
|
||||||
|
loudness = S_Voip_Loudness(snd_voip_showmeter.value>=2);
|
||||||
|
if (loudness >= 0)
|
||||||
|
{
|
||||||
|
int cw = 8;
|
||||||
|
int w;
|
||||||
|
int x=160;
|
||||||
|
int s, i;
|
||||||
|
float range = loudness/100.0f;
|
||||||
|
w = (5+16+1)*cw;
|
||||||
|
x -= w/2;
|
||||||
|
Draw_Character (x, y, 'M'); x+=cw;
|
||||||
|
Draw_Character (x, y, 'i'); x+=cw;
|
||||||
|
Draw_Character (x, y, 'c'); x+=cw;
|
||||||
|
x+=cw;
|
||||||
|
Draw_Character (x, y, 0xe080); x+=cw;
|
||||||
|
for (s=x,i=0 ; i<16 ; i++, x+=cw)
|
||||||
|
Draw_Character(x, y, 0xe081);
|
||||||
|
Draw_Character (x, y, 0xe082);
|
||||||
|
Draw_Character (s + (x-s) * range - cw/2, y, 0xe083);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
Sbar_Draw
|
Sbar_Draw
|
||||||
|
@ -941,6 +1004,13 @@ void Sbar_Draw (void)
|
||||||
|
|
||||||
GL_SetCanvas (CANVAS_DEFAULT); //johnfitz
|
GL_SetCanvas (CANVAS_DEFAULT); //johnfitz
|
||||||
|
|
||||||
|
if (sb_lines > 24)
|
||||||
|
Sbar_Voice(-32);
|
||||||
|
else if (sb_lines > 0)
|
||||||
|
Sbar_Voice(-8);
|
||||||
|
else
|
||||||
|
Sbar_Voice(16);
|
||||||
|
|
||||||
//johnfitz -- don't waste fillrate by clearing the area behind the sbar
|
//johnfitz -- don't waste fillrate by clearing the area behind the sbar
|
||||||
w = CLAMP (320.0f, scr_sbarscale.value * 320.0f, (float)glwidth);
|
w = CLAMP (320.0f, scr_sbarscale.value * 320.0f, (float)glwidth);
|
||||||
if (sb_lines && glwidth > w)
|
if (sb_lines && glwidth > w)
|
||||||
|
@ -1138,6 +1208,9 @@ void Sbar_DeathmatchOverlay (void)
|
||||||
top = Sbar_ColorForMap (top);
|
top = Sbar_ColorForMap (top);
|
||||||
bottom = Sbar_ColorForMap (bottom);
|
bottom = Sbar_ColorForMap (bottom);
|
||||||
|
|
||||||
|
if (S_Voip_Speaking(k)) //spike -- display an underlay for people who are speaking
|
||||||
|
Draw_Fill ( x, y, 320-x*2, 8, ((k+1)==cl.viewentity)?75:73, 1);
|
||||||
|
|
||||||
Draw_Fill ( x, y, 40, 4, top, 1); //johnfitz -- stretched overlays
|
Draw_Fill ( x, y, 40, 4, top, 1); //johnfitz -- stretched overlays
|
||||||
Draw_Fill ( x, y+4, 40, 4, bottom, 1); //johnfitz -- stretched overlays
|
Draw_Fill ( x, y+4, 40, 4, bottom, 1); //johnfitz -- stretched overlays
|
||||||
|
|
||||||
|
@ -1170,6 +1243,9 @@ void Sbar_DeathmatchOverlay (void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
sprintf (num, "%4i", s->ping);
|
||||||
|
M_PrintWhite (x-8*5, y, num); //johnfitz -- was Draw_String, changed for stretched overlays
|
||||||
|
|
||||||
// draw name
|
// draw name
|
||||||
M_Print (x+64, y, s->name); //johnfitz -- was Draw_String, changed for stretched overlays
|
M_Print (x+64, y, s->name); //johnfitz -- was Draw_String, changed for stretched overlays
|
||||||
|
|
||||||
|
@ -1177,6 +1253,13 @@ void Sbar_DeathmatchOverlay (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
GL_SetCanvas (CANVAS_SBAR); //johnfitz
|
GL_SetCanvas (CANVAS_SBAR); //johnfitz
|
||||||
|
|
||||||
|
if (!cls.message.cursize && cl.expectingpingtimes < realtime)
|
||||||
|
{
|
||||||
|
cl.expectingpingtimes = realtime + 5;
|
||||||
|
MSG_WriteByte (&cls.message, clc_stringcmd);
|
||||||
|
MSG_WriteString(&cls.message, "ping");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
102
Quake/server.h
102
Quake/server.h
|
@ -75,6 +75,25 @@ typedef struct
|
||||||
|
|
||||||
unsigned protocol; //johnfitz
|
unsigned protocol; //johnfitz
|
||||||
unsigned protocolflags;
|
unsigned protocolflags;
|
||||||
|
|
||||||
|
sizebuf_t multicast; // selectively copied to clients by the multicast builtin
|
||||||
|
byte multicast_buf[MAX_DATAGRAM];
|
||||||
|
|
||||||
|
const char *particle_precache[MAX_PARTICLETYPES]; // NULL terminated
|
||||||
|
|
||||||
|
entity_state_t *static_entities;
|
||||||
|
int num_statics;
|
||||||
|
int max_statics;
|
||||||
|
|
||||||
|
struct ambientsound_s
|
||||||
|
{
|
||||||
|
vec3_t origin;
|
||||||
|
unsigned int soundindex;
|
||||||
|
float volume;
|
||||||
|
float attenuation;
|
||||||
|
} *ambientsounds;
|
||||||
|
int num_ambients;
|
||||||
|
int max_ambients;
|
||||||
} server_t;
|
} server_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,9 +103,10 @@ typedef struct
|
||||||
typedef struct client_s
|
typedef struct client_s
|
||||||
{
|
{
|
||||||
qboolean active; // false = client is free
|
qboolean active; // false = client is free
|
||||||
qboolean spawned; // false = don't send datagrams
|
qboolean spawned; // false = don't send datagrams (set when client acked the first entities)
|
||||||
qboolean dropasap; // has been told to go to another level
|
qboolean dropasap; // has been told to go to another level
|
||||||
qboolean sendsignon; // only valid before spawned
|
int sendsignon; // only valid before spawned
|
||||||
|
int signonidx;
|
||||||
|
|
||||||
double last_message; // reliable messages must be sent
|
double last_message; // reliable messages must be sent
|
||||||
// periodically
|
// periodically
|
||||||
|
@ -111,6 +131,64 @@ typedef struct client_s
|
||||||
|
|
||||||
// client known data for deltas
|
// client known data for deltas
|
||||||
int old_frags;
|
int old_frags;
|
||||||
|
|
||||||
|
sizebuf_t datagram;
|
||||||
|
byte datagram_buf[MAX_DATAGRAM];
|
||||||
|
|
||||||
|
unsigned int limit_entities; //vanilla is 600
|
||||||
|
unsigned int limit_unreliable; //max allowed size for unreliables
|
||||||
|
unsigned int limit_reliable; //max (total) size of a reliable message.
|
||||||
|
unsigned int limit_models; //
|
||||||
|
unsigned int limit_sounds; //
|
||||||
|
|
||||||
|
qboolean pextknown;
|
||||||
|
unsigned int protocol_pext2;
|
||||||
|
unsigned int resendstats[MAX_CL_STATS/32]; //the stats which need to be resent.
|
||||||
|
int oldstats_i[MAX_CL_STATS]; //previous values of stats. if these differ from the current values, reflag resendstats.
|
||||||
|
float oldstats_f[MAX_CL_STATS]; //previous values of stats. if these differ from the current values, reflag resendstats.
|
||||||
|
struct entity_num_state_s{
|
||||||
|
unsigned int num; //ascending order, there can be gaps.
|
||||||
|
entity_state_t state;
|
||||||
|
} *previousentities;
|
||||||
|
size_t numpreviousentities;
|
||||||
|
size_t maxpreviousentities;
|
||||||
|
unsigned int snapshotresume;
|
||||||
|
unsigned int *pendingentities_bits; //UF_ flags for each entity
|
||||||
|
size_t numpendingentities; //realloc if too small
|
||||||
|
struct deltaframe_s
|
||||||
|
{ //quick overview of how this stuff actually works:
|
||||||
|
//when the server notices a gap in the ack sequence, we walk through the dropped frames and reflag everything that was dropped.
|
||||||
|
//if the server isn't tracking enough frames, then we just treat those as dropped;
|
||||||
|
//small note: when an entity is new, it re-flags itself as new for the next packet too, this reduces the immediate impact of packetloss on new entities.
|
||||||
|
//reflagged state includes stats updates, entity updates, and entity removes.
|
||||||
|
int sequence; //to see if its stale
|
||||||
|
float timestamp;
|
||||||
|
unsigned int resendstats[MAX_CL_STATS/32];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int num;
|
||||||
|
unsigned int bits;
|
||||||
|
} *ents;
|
||||||
|
int numents; //doesn't contain an entry for every entity, just ones that were sent this frame. no 0 bits
|
||||||
|
int maxents;
|
||||||
|
} *frames;
|
||||||
|
size_t numframes; //preallocated power-of-two
|
||||||
|
int lastacksequence;
|
||||||
|
int lastmovemessage;
|
||||||
|
|
||||||
|
client_voip_t voip; //spike -- for voip
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
char name[MAX_QPATH];
|
||||||
|
FILE *file;
|
||||||
|
qboolean started; //actually sending
|
||||||
|
unsigned int startpos; //within the pak, so we don't break stuff when seeking
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int sendpos; //file offset we last tried sending
|
||||||
|
unsigned int ackpos; //if they don't ack this properly, we restart sending from here instead.
|
||||||
|
//for more speed, the server should build a collection of blocks to track which parts were actually acked, thereby avoiding redundant resends, but in the intererest of simplicity...
|
||||||
|
} download;
|
||||||
|
qboolean knowntoqc; // putclientinserver was called
|
||||||
} client_t;
|
} client_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,6 +206,8 @@ typedef struct client_s
|
||||||
#define MOVETYPE_NOCLIP 8
|
#define MOVETYPE_NOCLIP 8
|
||||||
#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
|
#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
|
||||||
#define MOVETYPE_BOUNCE 10
|
#define MOVETYPE_BOUNCE 10
|
||||||
|
//#define MOVETYPE_EXT_BOUNCEMISSILE 11
|
||||||
|
#define MOVETYPE_EXT_FOLLOW 12
|
||||||
|
|
||||||
// edict->solid values
|
// edict->solid values
|
||||||
#define SOLID_NOT 0 // no interaction with other objects
|
#define SOLID_NOT 0 // no interaction with other objects
|
||||||
|
@ -135,6 +215,7 @@ typedef struct client_s
|
||||||
#define SOLID_BBOX 2 // touch on edge, block
|
#define SOLID_BBOX 2 // touch on edge, block
|
||||||
#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
|
#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
|
||||||
#define SOLID_BSP 4 // bsp clip, touch on edge, block
|
#define SOLID_BSP 4 // bsp clip, touch on edge, block
|
||||||
|
#define SOLID_EXT_CORPSE 5 // passes through slidebox+other corpses, but not bsp/bbox/triggers
|
||||||
|
|
||||||
// edict->deadflag values
|
// edict->deadflag values
|
||||||
#define DEAD_NO 0
|
#define DEAD_NO 0
|
||||||
|
@ -161,13 +242,6 @@ typedef struct client_s
|
||||||
#define FL_WATERJUMP 2048 // player jumping out of water
|
#define FL_WATERJUMP 2048 // player jumping out of water
|
||||||
#define FL_JUMPRELEASED 4096 // for jump debouncing
|
#define FL_JUMPRELEASED 4096 // for jump debouncing
|
||||||
|
|
||||||
// entity effects
|
|
||||||
|
|
||||||
#define EF_BRIGHTFIELD 1
|
|
||||||
#define EF_MUZZLEFLASH 2
|
|
||||||
#define EF_BRIGHTLIGHT 4
|
|
||||||
#define EF_DIMLIGHT 8
|
|
||||||
|
|
||||||
#define SPAWNFLAG_NOT_EASY 256
|
#define SPAWNFLAG_NOT_EASY 256
|
||||||
#define SPAWNFLAG_NOT_MEDIUM 512
|
#define SPAWNFLAG_NOT_MEDIUM 512
|
||||||
#define SPAWNFLAG_NOT_HARD 1024
|
#define SPAWNFLAG_NOT_HARD 1024
|
||||||
|
@ -194,11 +268,14 @@ extern edict_t *sv_player;
|
||||||
void SV_Init (void);
|
void SV_Init (void);
|
||||||
|
|
||||||
void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count);
|
void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count);
|
||||||
void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume,
|
void SV_StartSound (edict_t *entity, float *origin, int channel,
|
||||||
float attenuation);
|
const char *sample, int volume, float attenuation);
|
||||||
|
|
||||||
void SV_DropClient (qboolean crash);
|
void SV_DropClient (qboolean crash);
|
||||||
|
|
||||||
|
void SVFTE_Ack(client_t *client, int sequence);
|
||||||
|
void SVFTE_DestroyFrames(client_t *client);
|
||||||
|
void SV_BuildEntityState(edict_t *ent, entity_state_t *state);
|
||||||
void SV_SendClientMessages (void);
|
void SV_SendClientMessages (void);
|
||||||
void SV_ClearDatagram (void);
|
void SV_ClearDatagram (void);
|
||||||
|
|
||||||
|
@ -219,10 +296,11 @@ void SV_Physics (void);
|
||||||
qboolean SV_CheckBottom (edict_t *ent);
|
qboolean SV_CheckBottom (edict_t *ent);
|
||||||
qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink);
|
qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink);
|
||||||
|
|
||||||
void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg);
|
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
|
||||||
|
|
||||||
void SV_MoveToGoal (void);
|
void SV_MoveToGoal (void);
|
||||||
|
|
||||||
|
void SV_ConnectClient (int clientnum); //called from the netcode to add new clients. also called from pr_ext to spawn new botclients.
|
||||||
void SV_CheckForNewClients (void);
|
void SV_CheckForNewClients (void);
|
||||||
void SV_RunClients (void);
|
void SV_RunClients (void);
|
||||||
void SV_SaveSpawnparms ();
|
void SV_SaveSpawnparms ();
|
||||||
|
|
|
@ -45,7 +45,7 @@ static snd_codec_t *codecs;
|
||||||
S_CodecRegister
|
S_CodecRegister
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
static void S_CodecRegister(snd_codec_t *codec)
|
void S_CodecRegister(snd_codec_t *codec)
|
||||||
{
|
{
|
||||||
codec->next = codecs;
|
codec->next = codecs;
|
||||||
codecs = codec;
|
codecs = codec;
|
||||||
|
|
|
@ -24,6 +24,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
// snd_dma.c -- main control for any streaming sound output device
|
// snd_dma.c -- main control for any streaming sound output device
|
||||||
|
|
||||||
|
/* FIXME -- spike
|
||||||
|
** with SDL, the SDL api provides a callback that is called whenever SDL thinks more audio is needed
|
||||||
|
** if we were to move our mixing into the callback instead, we would obsolete _snd_mixahead and reduce audio latency as a result (instead of having to pre-mix audio just in case).
|
||||||
|
** this callback can typically also be assumed to be on another thread, so mixing audio there would result in a drop in cpu usage on the main thread, increasing framerates.
|
||||||
|
** typically quake's audio mixer isn't that expensive, but when you have maps with 1000 static sounds with 8-channel surround sound, things can start to get pricy.
|
||||||
|
**
|
||||||
|
** S_Update_ would become a stub, and we'd need to call SDL_LockAudio to block the callback from happening any time we change an audio channel.
|
||||||
|
** snd_mix.c would also need to be threadsafe with regard to the rest of the code
|
||||||
|
**
|
||||||
|
** alternatively, sdl2 provides a different audio api that more closely matches what we currently do, where we would directly submit audio (snd_mixahead would again be obsolete).
|
||||||
|
*/
|
||||||
|
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
#include "snd_codec.h"
|
#include "snd_codec.h"
|
||||||
#include "bgmusic.h"
|
#include "bgmusic.h"
|
||||||
|
@ -39,8 +51,9 @@ static void S_StopAllSoundsC (void);
|
||||||
// Internal sound data & structures
|
// Internal sound data & structures
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
|
|
||||||
channel_t snd_channels[MAX_CHANNELS];
|
channel_t *snd_channels;
|
||||||
int total_channels;
|
int total_channels;
|
||||||
|
int max_channels;
|
||||||
|
|
||||||
static int snd_blocked = 0;
|
static int snd_blocked = 0;
|
||||||
static qboolean snd_initialized = false;
|
static qboolean snd_initialized = false;
|
||||||
|
@ -52,6 +65,7 @@ vec3_t listener_origin;
|
||||||
vec3_t listener_forward;
|
vec3_t listener_forward;
|
||||||
vec3_t listener_right;
|
vec3_t listener_right;
|
||||||
vec3_t listener_up;
|
vec3_t listener_up;
|
||||||
|
float voicevolumescale = 1; //for audio ducking while speaking
|
||||||
|
|
||||||
#define sound_nominal_clip_dist 1000.0
|
#define sound_nominal_clip_dist 1000.0
|
||||||
|
|
||||||
|
@ -183,6 +197,8 @@ void S_Init (void)
|
||||||
Cvar_RegisterVariable(&snd_mixspeed);
|
Cvar_RegisterVariable(&snd_mixspeed);
|
||||||
Cvar_RegisterVariable(&snd_filterquality);
|
Cvar_RegisterVariable(&snd_filterquality);
|
||||||
|
|
||||||
|
S_Voip_Init();
|
||||||
|
|
||||||
if (safemode || COM_CheckParm("-nosound"))
|
if (safemode || COM_CheckParm("-nosound"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -401,11 +417,17 @@ void SND_Spatialize (channel_t *ch)
|
||||||
vec_t lscale, rscale, scale;
|
vec_t lscale, rscale, scale;
|
||||||
vec3_t source_vec;
|
vec3_t source_vec;
|
||||||
|
|
||||||
|
if (ch->entchannel == -2)
|
||||||
|
{
|
||||||
|
ch->leftvol = ch->master_vol; //voip comes out full volume
|
||||||
|
ch->rightvol = ch->master_vol;
|
||||||
|
return;
|
||||||
|
}
|
||||||
// anything coming from the view entity will always be full volume
|
// anything coming from the view entity will always be full volume
|
||||||
if (ch->entnum == cl.viewentity)
|
if (ch->entnum == cl.viewentity)
|
||||||
{
|
{
|
||||||
ch->leftvol = ch->master_vol;
|
ch->leftvol = ch->master_vol * voicevolumescale;
|
||||||
ch->rightvol = ch->master_vol;
|
ch->rightvol = ch->master_vol * voicevolumescale;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,12 +449,12 @@ void SND_Spatialize (channel_t *ch)
|
||||||
|
|
||||||
// add in distance effect
|
// add in distance effect
|
||||||
scale = (1.0 - dist) * rscale;
|
scale = (1.0 - dist) * rscale;
|
||||||
ch->rightvol = (int) (ch->master_vol * scale);
|
ch->rightvol = (int) (ch->master_vol * scale * voicevolumescale);
|
||||||
if (ch->rightvol < 0)
|
if (ch->rightvol < 0)
|
||||||
ch->rightvol = 0;
|
ch->rightvol = 0;
|
||||||
|
|
||||||
scale = (1.0 - dist) * lscale;
|
scale = (1.0 - dist) * lscale;
|
||||||
ch->leftvol = (int) (ch->master_vol * scale);
|
ch->leftvol = (int) (ch->master_vol * scale * voicevolumescale);
|
||||||
if (ch->leftvol < 0)
|
if (ch->leftvol < 0)
|
||||||
ch->leftvol = 0;
|
ch->leftvol = 0;
|
||||||
}
|
}
|
||||||
|
@ -532,20 +554,17 @@ void S_StopSound (int entnum, int entchannel)
|
||||||
|
|
||||||
void S_StopAllSounds (qboolean clear)
|
void S_StopAllSounds (qboolean clear)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!sound_started)
|
if (!sound_started)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
|
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
|
||||||
|
if (max_channels != total_channels + 64)
|
||||||
for (i = 0; i < MAX_CHANNELS; i++)
|
{ //shrink it if needed
|
||||||
{
|
max_channels = total_channels + 64;
|
||||||
if (snd_channels[i].sfx)
|
free(snd_channels);
|
||||||
snd_channels[i].sfx = NULL;
|
snd_channels = malloc(sizeof(channel_t) * max_channels);
|
||||||
}
|
}
|
||||||
|
memset(snd_channels, 0, max_channels * sizeof(channel_t));
|
||||||
memset(snd_channels, 0, MAX_CHANNELS * sizeof(channel_t));
|
|
||||||
|
|
||||||
if (clear)
|
if (clear)
|
||||||
S_ClearBuffer ();
|
S_ClearBuffer ();
|
||||||
|
@ -593,10 +612,18 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
|
||||||
if (!sfx)
|
if (!sfx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (total_channels == MAX_CHANNELS)
|
if (total_channels == max_channels)
|
||||||
{
|
{
|
||||||
Con_Printf ("total_channels == MAX_CHANNELS\n");
|
int nm = max_channels+64;
|
||||||
return;
|
ss = realloc(snd_channels, sizeof(*ss)*nm);
|
||||||
|
if (!ss)
|
||||||
|
{
|
||||||
|
Con_Printf ("unable to increase max_channels\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
snd_channels = ss;
|
||||||
|
memset(snd_channels+max_channels, 0, sizeof(*ss)*(nm-max_channels));
|
||||||
|
max_channels = nm;
|
||||||
}
|
}
|
||||||
|
|
||||||
ss = &snd_channels[total_channels];
|
ss = &snd_channels[total_channels];
|
||||||
|
@ -632,14 +659,15 @@ S_UpdateAmbientSounds
|
||||||
static void S_UpdateAmbientSounds (void)
|
static void S_UpdateAmbientSounds (void)
|
||||||
{
|
{
|
||||||
mleaf_t *l;
|
mleaf_t *l;
|
||||||
int vol, ambient_channel;
|
int ambient_channel;
|
||||||
channel_t *chan;
|
channel_t *chan;
|
||||||
|
static float vol, levels[NUM_AMBIENTS]; //Spike: fixing ambient levels not changing at high enough framerates due to integer precison.
|
||||||
|
|
||||||
// no ambients when disconnected
|
// no ambients when disconnected
|
||||||
if (cls.state != ca_connected)
|
if (cls.state != ca_connected || cls.signon != SIGNONS)
|
||||||
return;
|
return;
|
||||||
// calc ambient sound levels
|
// calc ambient sound levels
|
||||||
if (!cl.worldmodel)
|
if (!cl.worldmodel || cl.worldmodel->needload)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
l = Mod_PointInLeaf (listener_origin, cl.worldmodel);
|
l = Mod_PointInLeaf (listener_origin, cl.worldmodel);
|
||||||
|
@ -660,20 +688,20 @@ static void S_UpdateAmbientSounds (void)
|
||||||
vol = 0;
|
vol = 0;
|
||||||
|
|
||||||
// don't adjust volume too fast
|
// don't adjust volume too fast
|
||||||
if (chan->master_vol < vol)
|
if (levels[ambient_channel] < vol)
|
||||||
{
|
{
|
||||||
chan->master_vol += (int) (host_frametime * ambient_fade.value);
|
levels[ambient_channel] += (host_frametime * ambient_fade.value);
|
||||||
if (chan->master_vol > vol)
|
if (levels[ambient_channel] > vol)
|
||||||
chan->master_vol = vol;
|
levels[ambient_channel] = vol;
|
||||||
}
|
}
|
||||||
else if (chan->master_vol > vol)
|
else if (chan->master_vol > vol)
|
||||||
{
|
{
|
||||||
chan->master_vol -= (int) (host_frametime * ambient_fade.value);
|
levels[ambient_channel] -= (host_frametime * ambient_fade.value);
|
||||||
if (chan->master_vol < vol)
|
if (levels[ambient_channel] < vol)
|
||||||
chan->master_vol = vol;
|
levels[ambient_channel] = vol;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan->leftvol = chan->rightvol = chan->master_vol;
|
chan->leftvol = chan->rightvol = chan->master_vol = levels[ambient_channel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,35 +52,58 @@ static void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
|
||||||
sc->width = 1;
|
sc->width = 1;
|
||||||
else
|
else
|
||||||
sc->width = inwidth;
|
sc->width = inwidth;
|
||||||
sc->stereo = 0;
|
if (sc->stereo == 1)
|
||||||
|
{ //crappy approach to stereo - strip it out by merging left+right channels
|
||||||
|
sc->stereo = 0;
|
||||||
|
|
||||||
// resample / decimate to the current source rate
|
|
||||||
|
|
||||||
if (stepscale == 1 && inwidth == 1 && sc->width == 1)
|
|
||||||
{
|
|
||||||
// fast special case
|
|
||||||
for (i = 0; i < outcount; i++)
|
|
||||||
((signed char *)sc->data)[i] = (int)( (unsigned char)(data[i]) - 128);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// general case
|
|
||||||
samplefrac = 0;
|
samplefrac = 0;
|
||||||
fracstep = stepscale*256;
|
fracstep = stepscale*256;
|
||||||
for (i = 0; i < outcount; i++)
|
for (i = 0; i < outcount; i++)
|
||||||
{
|
{
|
||||||
srcsample = samplefrac >> 8;
|
srcsample = samplefrac >> 8;
|
||||||
|
srcsample<<=1;
|
||||||
samplefrac += fracstep;
|
samplefrac += fracstep;
|
||||||
if (inwidth == 2)
|
if (inwidth == 2)
|
||||||
sample = LittleShort ( ((short *)data)[srcsample] );
|
sample = LittleShort ( ((short *)data)[srcsample] ) + LittleShort ( ((short *)data)[srcsample+1] );
|
||||||
else
|
else
|
||||||
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
|
sample = ((int)( (unsigned char)(data[srcsample]) - 128) << 8) + ((int)( (unsigned char)(data[srcsample+1]) - 128) << 8);
|
||||||
|
sample /= 2;
|
||||||
if (sc->width == 2)
|
if (sc->width == 2)
|
||||||
((short *)sc->data)[i] = sample;
|
((short *)sc->data)[i] = sample;
|
||||||
else
|
else
|
||||||
((signed char *)sc->data)[i] = sample >> 8;
|
((signed char *)sc->data)[i] = sample >> 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// resample / decimate to the current source rate
|
||||||
|
|
||||||
|
if (stepscale == 1 && inwidth == 1 && sc->width == 1)
|
||||||
|
{
|
||||||
|
// fast special case
|
||||||
|
for (i = 0; i < outcount; i++)
|
||||||
|
((signed char *)sc->data)[i] = (int)( (unsigned char)(data[i]) - 128);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// general case
|
||||||
|
samplefrac = 0;
|
||||||
|
fracstep = stepscale*256;
|
||||||
|
for (i = 0; i < outcount; i++)
|
||||||
|
{
|
||||||
|
srcsample = samplefrac >> 8;
|
||||||
|
samplefrac += fracstep;
|
||||||
|
if (inwidth == 2)
|
||||||
|
sample = LittleShort ( ((short *)data)[srcsample] );
|
||||||
|
else
|
||||||
|
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
|
||||||
|
if (sc->width == 2)
|
||||||
|
((short *)sc->data)[i] = sample;
|
||||||
|
else
|
||||||
|
((signed char *)sc->data)[i] = sample >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -122,7 +145,7 @@ sfxcache_t *S_LoadSound (sfx_t *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
info = GetWavinfo (s->name, data, com_filesize);
|
info = GetWavinfo (s->name, data, com_filesize);
|
||||||
if (info.channels != 1)
|
if (info.channels != 1 && info.channels != 2)
|
||||||
{
|
{
|
||||||
Con_Printf ("%s is a stereo sample\n",s->name);
|
Con_Printf ("%s is a stereo sample\n",s->name);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -137,7 +160,7 @@ sfxcache_t *S_LoadSound (sfx_t *s)
|
||||||
stepscale = (float)info.rate / shm->speed;
|
stepscale = (float)info.rate / shm->speed;
|
||||||
len = info.samples / stepscale;
|
len = info.samples / stepscale;
|
||||||
|
|
||||||
len = len * info.width * info.channels;
|
len = len * info.width;// * info.channels;
|
||||||
|
|
||||||
if (info.samples == 0 || len == 0)
|
if (info.samples == 0 || len == 0)
|
||||||
{
|
{
|
||||||
|
@ -149,11 +172,11 @@ sfxcache_t *S_LoadSound (sfx_t *s)
|
||||||
if (!sc)
|
if (!sc)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
sc->length = info.samples;
|
sc->length = info.samples / info.channels;
|
||||||
sc->loopstart = info.loopstart;
|
sc->loopstart = info.loopstart;
|
||||||
sc->speed = info.rate;
|
sc->speed = info.rate;
|
||||||
sc->width = info.width;
|
sc->width = info.width;
|
||||||
sc->stereo = info.channels;
|
sc->stereo = info.channels-1;
|
||||||
|
|
||||||
ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
|
ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
|
||||||
|
|
||||||
|
|
|
@ -244,6 +244,8 @@ static void S_ApplyFilter(filter_t *filter, int *data, int stride, int count)
|
||||||
int parity;
|
int parity;
|
||||||
|
|
||||||
input = (float *) malloc(sizeof(float) * (filter->kernelsize + count));
|
input = (float *) malloc(sizeof(float) * (filter->kernelsize + count));
|
||||||
|
if (!input)
|
||||||
|
return;
|
||||||
|
|
||||||
// set up the input buffer
|
// set up the input buffer
|
||||||
// memory holds the previous filter->kernelsize samples of input.
|
// memory holds the previous filter->kernelsize samples of input.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
||||||
|
//spike -- this file contains prototypes+etc for voice chat.
|
||||||
|
//it should be fairly straight forward to integrate this into other engines, however, to implement it properly you'll need to deal with the whole pext2_voicechat handshake thing.
|
||||||
|
//for quakespasm-spiked this is already handled for entity deltas etc.
|
||||||
|
//you'll also need to figure out something with the 4 clientcommands that servers might receive.
|
||||||
|
//to test, cl_voip_test 1;sv_voip_echo 0;+voip should start playing even without any protocol extensions. then move on to cl_voip_test 0;sv_voip_echo 1;+voip once you have protocol stuff working.
|
||||||
|
//you'll also want to add the various voip settings to the menu, especially cl_voip_play (slider 0-1), cl_voip_send (boolean), +voip binding.
|
||||||
|
|
||||||
|
//defined elsewhere
|
||||||
|
//#define svcfte_voicechat 84
|
||||||
|
//#define clcfte_voicechat 83
|
||||||
|
struct client_s;
|
||||||
|
|
||||||
|
|
||||||
|
//client functions
|
||||||
|
void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf); //call from CL_SendMove (null buf if not connecting, grabs new data, encodes, and writes into the buffer)
|
||||||
|
void S_Voip_MapChange(void); //call from end of CL_ParseServerinfo (tells server to reenable voice chat)
|
||||||
|
void S_Voip_Parse(void); //call from CL_ParseServerMessage+svcfte_voicechat. processes voip data from the server
|
||||||
|
int S_Voip_Loudness(qboolean ignorevad); //for sbar stuff, if you want to draw some mic-level bar (returns 0-100, or -1 for not transmitting)
|
||||||
|
qboolean S_Voip_Speaking(unsigned int plno); //for sbar stuff, if you want to query which other players are speaking (add a scoreboard back-colour or something).
|
||||||
|
void S_Voip_Init(void); //call from S_Init, registers client cvars+commands
|
||||||
|
|
||||||
|
//server functions
|
||||||
|
void SV_VoiceInit(void); //call from SV_Init, registers server cvars+commands
|
||||||
|
void SV_VoiceInitClient(struct client_s *client); //call from start of SV_SendServerinfo, disables voice chat until the client is ready to re-enable it
|
||||||
|
void SV_VoiceSendPacket(struct client_s *client, sizebuf_t *buf); //call from near end of SV_SendClientDatagram, to forward voice data to other clients
|
||||||
|
void SV_VoiceReadPacket(struct client_s *client); //call from SV_ReadClientMessage+clcfte_voicechat. processes voip data from clients and figures out which clients to forward to
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int read; /*place in ring*/
|
||||||
|
unsigned char mute[MAX_SCOREBOARD/8]; /*which other clients should be muted for this player, reducing bandwidth from annoying cunts*/
|
||||||
|
qboolean active; /*client wants to hear other people*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/*should we add one to respond to the last speaker? or should that be an automagic +voip_reply instead?*/
|
||||||
|
VT_TEAM,
|
||||||
|
VT_ALL,
|
||||||
|
VT_NONMUTED, /*cheap, but allows custom private channels with no external pesters*/
|
||||||
|
VT_PLAYERSLOT0
|
||||||
|
/*player0+...*/
|
||||||
|
} target;
|
||||||
|
} client_voip_t; //embedded within struct client_s as a member named voip
|
File diff suppressed because it is too large
Load Diff
1991
Quake/sv_main.c
1991
Quake/sv_main.c
File diff suppressed because it is too large
Load Diff
113
Quake/sv_phys.c
113
Quake/sv_phys.c
|
@ -47,6 +47,7 @@ cvar_t sv_gravity = {"sv_gravity","800",CVAR_NOTIFY|CVAR_SERVERINFO};
|
||||||
cvar_t sv_maxvelocity = {"sv_maxvelocity","2000",CVAR_NONE};
|
cvar_t sv_maxvelocity = {"sv_maxvelocity","2000",CVAR_NONE};
|
||||||
cvar_t sv_nostep = {"sv_nostep","0",CVAR_NONE};
|
cvar_t sv_nostep = {"sv_nostep","0",CVAR_NONE};
|
||||||
cvar_t sv_freezenonclients = {"sv_freezenonclients","0",CVAR_NONE};
|
cvar_t sv_freezenonclients = {"sv_freezenonclients","0",CVAR_NONE};
|
||||||
|
cvar_t sv_gameplayfix_spawnbeforethinks = {"sv_gameplayfix_spawnbeforethinks","0",CVAR_NONE};
|
||||||
|
|
||||||
|
|
||||||
#define MOVE_EPSILON 0.01
|
#define MOVE_EPSILON 0.01
|
||||||
|
@ -388,7 +389,7 @@ void SV_AddGravity (edict_t *ent)
|
||||||
float ent_gravity;
|
float ent_gravity;
|
||||||
eval_t *val;
|
eval_t *val;
|
||||||
|
|
||||||
val = GetEdictFieldValue(ent, "gravity");
|
val = GetEdictFieldValue(ent, pr_extfields.gravity);
|
||||||
if (val && val->_float)
|
if (val && val->_float)
|
||||||
ent_gravity = val->_float;
|
ent_gravity = val->_float;
|
||||||
else
|
else
|
||||||
|
@ -453,6 +454,7 @@ void SV_PushMove (edict_t *pusher, float movetime)
|
||||||
edict_t **moved_edict; //johnfitz -- dynamically allocate
|
edict_t **moved_edict; //johnfitz -- dynamically allocate
|
||||||
vec3_t *moved_from; //johnfitz -- dynamically allocate
|
vec3_t *moved_from; //johnfitz -- dynamically allocate
|
||||||
int mark; //johnfitz
|
int mark; //johnfitz
|
||||||
|
float solid_backup;
|
||||||
|
|
||||||
if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
|
if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
|
||||||
{
|
{
|
||||||
|
@ -519,13 +521,23 @@ void SV_PushMove (edict_t *pusher, float movetime)
|
||||||
moved_edict[num_moved] = check;
|
moved_edict[num_moved] = check;
|
||||||
num_moved++;
|
num_moved++;
|
||||||
|
|
||||||
// try moving the contacted entity
|
//QIP fix for end.bsp
|
||||||
pusher->v.solid = SOLID_NOT;
|
solid_backup = pusher->v.solid;
|
||||||
SV_PushEntity (check, move);
|
if ( solid_backup == SOLID_BSP // everything that blocks: bsp models = map brushes = doors, plats, etc.
|
||||||
pusher->v.solid = SOLID_BSP;
|
|| solid_backup == SOLID_BBOX // normally boxes
|
||||||
|
|| solid_backup == SOLID_SLIDEBOX ) // normally monsters
|
||||||
|
{
|
||||||
|
// try moving the contacted entity
|
||||||
|
pusher->v.solid = SOLID_NOT;
|
||||||
|
SV_PushEntity (check, move);
|
||||||
|
pusher->v.solid = solid_backup;
|
||||||
|
|
||||||
|
// if it is still inside the pusher, block
|
||||||
|
block = SV_TestEntityPosition (check);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
block = NULL;
|
||||||
|
|
||||||
// if it is still inside the pusher, block
|
|
||||||
block = SV_TestEntityPosition (check);
|
|
||||||
if (block)
|
if (block)
|
||||||
{ // fail the move
|
{ // fail the move
|
||||||
if (check->v.mins[0] == check->v.maxs[0])
|
if (check->v.mins[0] == check->v.maxs[0])
|
||||||
|
@ -907,6 +919,9 @@ void SV_Physics_Client (edict_t *ent, int num)
|
||||||
if ( ! svs.clients[num-1].active )
|
if ( ! svs.clients[num-1].active )
|
||||||
return; // unconnected slot
|
return; // unconnected slot
|
||||||
|
|
||||||
|
if (!svs.clients[num-1].knowntoqc && sv_gameplayfix_spawnbeforethinks.value)
|
||||||
|
return; //don't spam prethinks before we called putclientinserver.
|
||||||
|
|
||||||
//
|
//
|
||||||
// call standard client pre-think
|
// call standard client pre-think
|
||||||
//
|
//
|
||||||
|
@ -956,7 +971,7 @@ void SV_Physics_Client (edict_t *ent, int num)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
|
Host_EndGame ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1034,7 +1049,7 @@ void SV_CheckWaterTransition (edict_t *ent)
|
||||||
{
|
{
|
||||||
if (ent->v.watertype == CONTENTS_EMPTY)
|
if (ent->v.watertype == CONTENTS_EMPTY)
|
||||||
{ // just crossed into water
|
{ // just crossed into water
|
||||||
SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
|
SV_StartSound (ent, NULL, 0, "misc/h2ohit1.wav", 255, 1);
|
||||||
}
|
}
|
||||||
ent->v.watertype = cont;
|
ent->v.watertype = cont;
|
||||||
ent->v.waterlevel = 1;
|
ent->v.waterlevel = 1;
|
||||||
|
@ -1043,7 +1058,7 @@ void SV_CheckWaterTransition (edict_t *ent)
|
||||||
{
|
{
|
||||||
if (ent->v.watertype != CONTENTS_EMPTY)
|
if (ent->v.watertype != CONTENTS_EMPTY)
|
||||||
{ // just crossed into water
|
{ // just crossed into water
|
||||||
SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
|
SV_StartSound (ent, NULL, 0, "misc/h2ohit1.wav", 255, 1);
|
||||||
}
|
}
|
||||||
ent->v.watertype = CONTENTS_EMPTY;
|
ent->v.watertype = CONTENTS_EMPTY;
|
||||||
ent->v.waterlevel = cont;
|
ent->v.waterlevel = cont;
|
||||||
|
@ -1112,6 +1127,55 @@ void SV_Physics_Toss (edict_t *ent)
|
||||||
SV_CheckWaterTransition (ent);
|
SV_CheckWaterTransition (ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
SV_Physics_Follow
|
||||||
|
|
||||||
|
Entities that are "stuck" to another entity
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
static void SV_Physics_Follow (edict_t *ent)
|
||||||
|
{
|
||||||
|
vec3_t vf, vr, vu, angles, v;
|
||||||
|
edict_t *e;
|
||||||
|
|
||||||
|
// regular thinking
|
||||||
|
if (!SV_RunThink (ent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
|
||||||
|
e = PROG_TO_EDICT(ent->v.aiment);
|
||||||
|
if (e->v.angles[0] == ent->v.punchangle[0] && e->v.angles[1] == ent->v.punchangle[1] && e->v.angles[2] == ent->v.punchangle[2])
|
||||||
|
{
|
||||||
|
// quick case for no rotation
|
||||||
|
VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
angles[0] = -ent->v.punchangle[0];
|
||||||
|
angles[1] = ent->v.punchangle[1];
|
||||||
|
angles[2] = ent->v.punchangle[2];
|
||||||
|
AngleVectors (angles, vf, vr, vu);
|
||||||
|
v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
|
||||||
|
v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
|
||||||
|
v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
|
||||||
|
angles[0] = -e->v.angles[0];
|
||||||
|
angles[1] = e->v.angles[1];
|
||||||
|
angles[2] = e->v.angles[2];
|
||||||
|
AngleVectors (angles, vf, vr, vu);
|
||||||
|
ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
|
||||||
|
ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
|
||||||
|
ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
|
||||||
|
}
|
||||||
|
VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
|
||||||
|
SV_LinkEdict (ent, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============================================================================
|
===============================================================================
|
||||||
|
|
||||||
|
@ -1151,7 +1215,7 @@ void SV_Physics_Step (edict_t *ent)
|
||||||
if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
|
if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
|
||||||
{
|
{
|
||||||
if (hitsound)
|
if (hitsound)
|
||||||
SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
|
SV_StartSound (ent, NULL, 0, "demon/dland2.wav", 255, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,9 +1254,9 @@ void SV_Physics (void)
|
||||||
ent = sv.edicts;
|
ent = sv.edicts;
|
||||||
|
|
||||||
if (sv_freezenonclients.value)
|
if (sv_freezenonclients.value)
|
||||||
entity_cap = svs.maxclients + 1; // Only run physics on clients and the world
|
entity_cap = svs.maxclients + 1; // Only run physics on clients and the world
|
||||||
else
|
else
|
||||||
entity_cap = sv.num_edicts;
|
entity_cap = sv.num_edicts;
|
||||||
|
|
||||||
//for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
|
//for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
|
||||||
for (i=0 ; i<entity_cap ; i++, ent = NEXT_EDICT(ent))
|
for (i=0 ; i<entity_cap ; i++, ent = NEXT_EDICT(ent))
|
||||||
|
@ -1220,13 +1284,34 @@ void SV_Physics (void)
|
||||||
|| ent->v.movetype == MOVETYPE_FLY
|
|| ent->v.movetype == MOVETYPE_FLY
|
||||||
|| ent->v.movetype == MOVETYPE_FLYMISSILE)
|
|| ent->v.movetype == MOVETYPE_FLYMISSILE)
|
||||||
SV_Physics_Toss (ent);
|
SV_Physics_Toss (ent);
|
||||||
|
else if (ent->v.movetype == MOVETYPE_EXT_FOLLOW)
|
||||||
|
SV_Physics_Follow (ent);
|
||||||
|
else if (ent->v.movetype == MOVETYPE_WALK)
|
||||||
|
{
|
||||||
|
if (SV_RunThink (ent))
|
||||||
|
{
|
||||||
|
if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
|
||||||
|
SV_AddGravity (ent);
|
||||||
|
SV_CheckStuck (ent);
|
||||||
|
SV_WalkMove (ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
|
Host_EndGame ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pr_global_struct->force_retouch)
|
if (pr_global_struct->force_retouch)
|
||||||
pr_global_struct->force_retouch--;
|
pr_global_struct->force_retouch--;
|
||||||
|
|
||||||
|
|
||||||
|
if (pr_extfuncs.endframe)
|
||||||
|
{
|
||||||
|
pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
|
||||||
|
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
|
||||||
|
pr_global_struct->time = sv.time;
|
||||||
|
PR_ExecuteProgram (pr_extfuncs.endframe);
|
||||||
|
}
|
||||||
|
|
||||||
if (!sv_freezenonclients.value)
|
if (!sv_freezenonclients.value)
|
||||||
sv.time += host_frametime;
|
sv.time += host_frametime;
|
||||||
}
|
}
|
||||||
|
|
283
Quake/sv_user.c
283
Quake/sv_user.c
|
@ -439,37 +439,92 @@ void SV_ReadClientMove (usercmd_t *move)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
vec3_t angle;
|
vec3_t angle;
|
||||||
int bits;
|
int buttonbits;
|
||||||
|
int newimpulse;
|
||||||
|
eval_t *eval;
|
||||||
|
qboolean drop = false;
|
||||||
|
float timestamp;
|
||||||
|
vec3_t movevalues;
|
||||||
|
int sequence;
|
||||||
|
eval_t *val;
|
||||||
|
|
||||||
// read ping time
|
if (host_client->protocol_pext2 & PEXT2_PREDINFO)
|
||||||
host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]
|
{
|
||||||
= sv.time - MSG_ReadFloat ();
|
i = (unsigned short)MSG_ReadShort();
|
||||||
host_client->num_pings++;
|
sequence = (host_client->lastmovemessage & 0xffff0000) | (i&0xffff);
|
||||||
|
|
||||||
// read current angles
|
//tollerance of a few old frames, so we can have redundancy for packetloss
|
||||||
|
if (sequence+0x100 < host_client->lastmovemessage)
|
||||||
|
sequence += 0x10000;
|
||||||
|
|
||||||
|
if (sequence <= host_client->lastmovemessage)
|
||||||
|
drop = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sequence = 0;
|
||||||
|
|
||||||
|
//read the data
|
||||||
|
timestamp = MSG_ReadFloat();
|
||||||
for (i=0 ; i<3 ; i++)
|
for (i=0 ; i<3 ; i++)
|
||||||
//johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE
|
{
|
||||||
if (sv.protocol == PROTOCOL_NETQUAKE)
|
if (sv.protocol == PROTOCOL_NETQUAKE && !(host_client->protocol_pext2 & PEXT2_PREDINFO) && !NET_QSocketGetProQuakeAngleHack(host_client->netconnection))
|
||||||
angle[i] = MSG_ReadAngle (sv.protocolflags);
|
angle[i] = MSG_ReadAngle (sv.protocolflags);
|
||||||
else
|
else
|
||||||
angle[i] = MSG_ReadAngle16 (sv.protocolflags);
|
angle[i] = MSG_ReadAngle16 (sv.protocolflags); //johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE
|
||||||
//johnfitz
|
}
|
||||||
|
movevalues[0] = MSG_ReadShort ();
|
||||||
|
movevalues[1] = MSG_ReadShort ();
|
||||||
|
movevalues[2] = MSG_ReadShort ();
|
||||||
|
buttonbits = MSG_ReadByte();
|
||||||
|
newimpulse = MSG_ReadByte();
|
||||||
|
|
||||||
|
if (drop)
|
||||||
|
return; //okay, we don't care about that then
|
||||||
|
|
||||||
|
// calc ping times
|
||||||
|
host_client->lastmovemessage = sequence;
|
||||||
|
if (!(host_client->protocol_pext2 & PEXT2_PREDINFO))
|
||||||
|
{
|
||||||
|
host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]
|
||||||
|
= sv.time - timestamp;
|
||||||
|
host_client->num_pings++;
|
||||||
|
} //otherwise time is still useful for determining the input frame's time value
|
||||||
|
|
||||||
|
// read movement
|
||||||
VectorCopy (angle, host_client->edict->v.v_angle);
|
VectorCopy (angle, host_client->edict->v.v_angle);
|
||||||
|
move->forwardmove = movevalues[0];
|
||||||
// read movement
|
move->sidemove = movevalues[1];
|
||||||
move->forwardmove = MSG_ReadShort ();
|
move->upmove = movevalues[2];
|
||||||
move->sidemove = MSG_ReadShort ();
|
|
||||||
move->upmove = MSG_ReadShort ();
|
|
||||||
|
|
||||||
// read buttons
|
// read buttons
|
||||||
bits = MSG_ReadByte ();
|
host_client->edict->v.button0 = (buttonbits & 1)>>0;
|
||||||
host_client->edict->v.button0 = bits & 1;
|
//button1 was meant to be 'use', but got reused by too many mods to get implemented now
|
||||||
host_client->edict->v.button2 = (bits & 2)>>1;
|
host_client->edict->v.button2 = (buttonbits & 2)>>1;
|
||||||
|
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button3)))
|
||||||
|
val->_float = (buttonbits & 4)>>2;
|
||||||
|
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button4)))
|
||||||
|
val->_float = (buttonbits & 8)>>3;
|
||||||
|
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button5)))
|
||||||
|
val->_float = (buttonbits & 0x10)>>4;
|
||||||
|
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button6)))
|
||||||
|
val->_float = (buttonbits & 0x20)>>5;
|
||||||
|
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button7)))
|
||||||
|
val->_float = (buttonbits & 0x40)>>6;
|
||||||
|
if ((val = GetEdictFieldValue(host_client->edict, pr_extfields.button8)))
|
||||||
|
val->_float = (buttonbits & 0x80)>>7;
|
||||||
|
|
||||||
i = MSG_ReadByte ();
|
if (newimpulse)
|
||||||
if (i)
|
host_client->edict->v.impulse = newimpulse;
|
||||||
host_client->edict->v.impulse = i;
|
|
||||||
|
eval = GetEdictFieldValue(host_client->edict, pr_extfields.movement);
|
||||||
|
if (eval)
|
||||||
|
{
|
||||||
|
eval->vector[0] = move->forwardmove;
|
||||||
|
eval->vector[1] = move->sidemove;
|
||||||
|
eval->vector[2] = move->upmove;
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: attempt to apply physics command now, if the mod has custom physics+csqc-prediction
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -481,110 +536,76 @@ Returns false if the client should be killed
|
||||||
*/
|
*/
|
||||||
qboolean SV_ReadClientMessage (void)
|
qboolean SV_ReadClientMessage (void)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
int ccmd;
|
int ccmd;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
do
|
MSG_BeginReading ();
|
||||||
|
|
||||||
|
while (1)
|
||||||
{
|
{
|
||||||
nextmsg:
|
if (!host_client->active)
|
||||||
ret = NET_GetMessage (host_client->netconnection);
|
return false; // a command caused an error
|
||||||
if (ret == -1)
|
|
||||||
|
if (msg_badread)
|
||||||
{
|
{
|
||||||
Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");
|
Sys_Printf ("SV_ReadClientMessage: badread\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ret)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
MSG_BeginReading ();
|
ccmd = MSG_ReadChar ();
|
||||||
|
|
||||||
while (1)
|
switch (ccmd)
|
||||||
{
|
{
|
||||||
if (!host_client->active)
|
case -1:
|
||||||
return false; // a command caused an error
|
return true; //msg_badread, meaning we just hit eof.
|
||||||
|
|
||||||
if (msg_badread)
|
default:
|
||||||
{
|
Sys_Printf ("SV_ReadClientMessage: unknown command char\n");
|
||||||
Sys_Printf ("SV_ReadClientMessage: badread\n");
|
return false;
|
||||||
return false;
|
|
||||||
|
case clc_nop:
|
||||||
|
// Sys_Printf ("clc_nop\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case clc_stringcmd:
|
||||||
|
s = MSG_ReadString ();
|
||||||
|
if (q_strncasecmp(s, "spawn", 5) && q_strncasecmp(s, "begin", 5) && q_strncasecmp(s, "prespawn", 8) && pr_extfuncs.parseclientcommand)
|
||||||
|
{ //the spawn/begin/prespawn are because of numerous mods that disobey the rules.
|
||||||
|
//at a minimum, we must be able to join the server, so that we can see any sprints/bprints (because dprint sucks, yes there's proper ways to deal with this, but moders don't always know them).
|
||||||
|
client_t *ohc = host_client;
|
||||||
|
G_INT(OFS_PARM0) = PR_SetEngineString(s);
|
||||||
|
pr_global_struct->time = sv.time;
|
||||||
|
pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
|
||||||
|
PR_ExecuteProgram(pr_extfuncs.parseclientcommand);
|
||||||
|
host_client = ohc;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
Cmd_ExecuteString (s, src_client);
|
||||||
|
break;
|
||||||
|
|
||||||
ccmd = MSG_ReadChar ();
|
case clc_disconnect:
|
||||||
|
// Sys_Printf ("SV_ReadClientMessage: client disconnected\n");
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (ccmd)
|
case clc_move:
|
||||||
{
|
if (!host_client->spawned)
|
||||||
case -1:
|
return true; //this is to suck up any stale moves on map changes, so we don't get confused (quite so easily) when protocols are changed between maps
|
||||||
goto nextmsg; // end of message
|
SV_ReadClientMove (&host_client->cmd);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
case clcdp_ackframe:
|
||||||
Sys_Printf ("SV_ReadClientMessage: unknown command char\n");
|
SVFTE_Ack(host_client, MSG_ReadLong());
|
||||||
return false;
|
break;
|
||||||
|
|
||||||
case clc_nop:
|
case clcdp_ackdownloaddata:
|
||||||
// Sys_Printf ("clc_nop\n");
|
Host_DownloadAck(host_client);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case clc_stringcmd:
|
case clcfte_voicechat:
|
||||||
s = MSG_ReadString ();
|
SV_VoiceReadPacket(host_client);
|
||||||
ret = 0;
|
break;
|
||||||
if (q_strncasecmp(s, "status", 6) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "god", 3) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "notarget", 8) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "fly", 3) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "name", 4) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "noclip", 6) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "setpos", 6) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "say", 3) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "say_team", 8) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "tell", 4) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "color", 5) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "kill", 4) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "pause", 5) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "spawn", 5) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "begin", 5) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "prespawn", 8) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "kick", 4) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "ping", 4) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "give", 4) == 0)
|
|
||||||
ret = 1;
|
|
||||||
else if (q_strncasecmp(s, "ban", 3) == 0)
|
|
||||||
ret = 1;
|
|
||||||
|
|
||||||
if (ret == 1)
|
|
||||||
Cmd_ExecuteString (s, src_client);
|
|
||||||
else
|
|
||||||
Con_DPrintf("%s tried to %s\n", host_client->name, s);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case clc_disconnect:
|
|
||||||
// Sys_Printf ("SV_ReadClientMessage: client disconnected\n");
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case clc_move:
|
|
||||||
SV_ReadClientMove (&host_client->cmd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} while (ret == 1);
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -599,6 +620,31 @@ void SV_RunClients (void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
//receive from clients first
|
||||||
|
//Spike -- reworked this to query the network code for an active connection.
|
||||||
|
//this allows the network code to serve multiple clients with the same listening port.
|
||||||
|
//this solves server-side nats, which is important for coop etc.
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
struct qsocket_s *sock = NET_GetServerMessage();
|
||||||
|
if (!sock)
|
||||||
|
break; //no more this frame
|
||||||
|
|
||||||
|
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
||||||
|
{
|
||||||
|
if (host_client->netconnection == sock)
|
||||||
|
{
|
||||||
|
sv_player = host_client->edict;
|
||||||
|
if (!SV_ReadClientMessage ())
|
||||||
|
{
|
||||||
|
SV_DropClient (false); // client misbehaved...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//then do the per-frame stuff
|
||||||
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
||||||
{
|
{
|
||||||
if (!host_client->active)
|
if (!host_client->active)
|
||||||
|
@ -606,12 +652,6 @@ void SV_RunClients (void)
|
||||||
|
|
||||||
sv_player = host_client->edict;
|
sv_player = host_client->edict;
|
||||||
|
|
||||||
if (!SV_ReadClientMessage ())
|
|
||||||
{
|
|
||||||
SV_DropClient (false); // client misbehaved...
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!host_client->spawned)
|
if (!host_client->spawned)
|
||||||
{
|
{
|
||||||
// clear client movement until a new packet is received
|
// clear client movement until a new packet is received
|
||||||
|
@ -619,6 +659,23 @@ void SV_RunClients (void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!host_client->netconnection)
|
||||||
|
{
|
||||||
|
//botclients can't receive packets. don't even try.
|
||||||
|
//not sure where to put this code, but here seems sane enough.
|
||||||
|
//fill in the user's desired stuff according to a few things.
|
||||||
|
eval_t *ev = GetEdictFieldValue(host_client->edict, pr_extfields.movement);
|
||||||
|
if (ev) //.movement normally works the other way around. oh well.
|
||||||
|
{
|
||||||
|
host_client->cmd.forwardmove = ev->vector[0];
|
||||||
|
host_client->cmd.sidemove = ev->vector[1];
|
||||||
|
host_client->cmd.upmove = ev->vector[2];
|
||||||
|
}
|
||||||
|
host_client->cmd.viewangles[0] = host_client->edict->v.v_angle[0];
|
||||||
|
host_client->cmd.viewangles[1] = host_client->edict->v.v_angle[1];
|
||||||
|
host_client->cmd.viewangles[2] = host_client->edict->v.v_angle[2];
|
||||||
|
}
|
||||||
|
|
||||||
// always pause in single player if in console or menus
|
// always pause in single player if in console or menus
|
||||||
if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
|
if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
|
||||||
SV_ClientThink ();
|
SV_ClientThink ();
|
||||||
|
|
|
@ -33,8 +33,9 @@ void Sys_Init (void);
|
||||||
// returns the file size or -1 if file is not present.
|
// returns the file size or -1 if file is not present.
|
||||||
// the file should be in BINARY mode for stupid OSs that care
|
// the file should be in BINARY mode for stupid OSs that care
|
||||||
int Sys_FileOpenRead (const char *path, int *hndl);
|
int Sys_FileOpenRead (const char *path, int *hndl);
|
||||||
|
|
||||||
int Sys_FileOpenWrite (const char *path);
|
int Sys_FileOpenWrite (const char *path);
|
||||||
|
int Sys_FileOpenStdio (FILE *file);
|
||||||
|
|
||||||
void Sys_FileClose (int handle);
|
void Sys_FileClose (int handle);
|
||||||
void Sys_FileSeek (int handle, int position);
|
void Sys_FileSeek (int handle, int position);
|
||||||
int Sys_FileRead (int handle, void *dest, int count);
|
int Sys_FileRead (int handle, void *dest, int count);
|
||||||
|
|
|
@ -119,6 +119,14 @@ int Sys_FileOpenWrite (const char *path)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Sys_FileOpenStdio (FILE *file)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
i = findhandle ();
|
||||||
|
sys_handles[i] = file;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
void Sys_FileClose (int handle)
|
void Sys_FileClose (int handle)
|
||||||
{
|
{
|
||||||
fclose (sys_handles[handle]);
|
fclose (sys_handles[handle]);
|
||||||
|
@ -382,6 +390,7 @@ void Sys_Error (const char *error, ...)
|
||||||
va_end (argptr);
|
va_end (argptr);
|
||||||
|
|
||||||
fputs (errortxt1, stderr);
|
fputs (errortxt1, stderr);
|
||||||
|
Con_Redirect(NULL);
|
||||||
Host_Shutdown ();
|
Host_Shutdown ();
|
||||||
fputs (errortxt2, stderr);
|
fputs (errortxt2, stderr);
|
||||||
fputs (text, stderr);
|
fputs (text, stderr);
|
||||||
|
|
|
@ -118,6 +118,14 @@ int Sys_FileOpenWrite (const char *path)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Sys_FileOpenStdio (FILE *file)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
i = findhandle ();
|
||||||
|
sys_handles[i] = file;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
void Sys_FileClose (int handle)
|
void Sys_FileClose (int handle)
|
||||||
{
|
{
|
||||||
fclose (sys_handles[handle]);
|
fclose (sys_handles[handle]);
|
||||||
|
@ -304,6 +312,8 @@ void Sys_Error (const char *error, ...)
|
||||||
q_vsnprintf (text, sizeof(text), error, argptr);
|
q_vsnprintf (text, sizeof(text), error, argptr);
|
||||||
va_end (argptr);
|
va_end (argptr);
|
||||||
|
|
||||||
|
Con_Redirect(NULL);
|
||||||
|
|
||||||
if (isDedicated)
|
if (isDedicated)
|
||||||
WriteFile (houtput, errortxt1, strlen(errortxt1), &dummy, NULL);
|
WriteFile (houtput, errortxt1, strlen(errortxt1), &dummy, NULL);
|
||||||
/* SDL will put these into its own stderr log,
|
/* SDL will put these into its own stderr log,
|
||||||
|
@ -338,7 +348,14 @@ void Sys_Printf (const char *fmt, ...)
|
||||||
|
|
||||||
if (isDedicated)
|
if (isDedicated)
|
||||||
{
|
{
|
||||||
WriteFile(houtput, text, strlen(text), &dummy, NULL);
|
if (*text == 1 || *text == 2)
|
||||||
|
{ //mostly for Con_[D]Warning
|
||||||
|
SetConsoleTextAttribute(houtput, FOREGROUND_RED);
|
||||||
|
WriteFile(houtput, text+1, strlen(text+1), &dummy, NULL);
|
||||||
|
SetConsoleTextAttribute(houtput, FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
WriteFile(houtput, text, strlen(text), &dummy, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
53
Quake/view.c
53
Quake/view.c
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
#include "quakedef.h"
|
#include "quakedef.h"
|
||||||
|
|
||||||
|
extern qboolean premul_hud;
|
||||||
/*
|
/*
|
||||||
|
|
||||||
The view is allowed to move slightly from it's true position for bobbing,
|
The view is allowed to move slightly from it's true position for bobbing,
|
||||||
|
@ -208,7 +209,7 @@ void V_DriftPitch (void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
delta = cl.idealpitch - cl.viewangles[PITCH];
|
delta = cl.statsf[STAT_IDEALPITCH] - cl.viewangles[PITCH];
|
||||||
|
|
||||||
if (!delta)
|
if (!delta)
|
||||||
{
|
{
|
||||||
|
@ -312,7 +313,7 @@ void V_ParseDamage (void)
|
||||||
//
|
//
|
||||||
// calculate view angle kicks
|
// calculate view angle kicks
|
||||||
//
|
//
|
||||||
ent = &cl_entities[cl.viewentity];
|
ent = &cl.entities[cl.viewentity];
|
||||||
|
|
||||||
VectorSubtract (from, ent->origin, from);
|
VectorSubtract (from, ent->origin, from);
|
||||||
VectorNormalize (from);
|
VectorNormalize (from);
|
||||||
|
@ -352,10 +353,20 @@ When you run over an item, the server sends this command
|
||||||
*/
|
*/
|
||||||
void V_BonusFlash_f (void)
|
void V_BonusFlash_f (void)
|
||||||
{
|
{
|
||||||
cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
|
if (Cmd_Argc() >= 5)
|
||||||
cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
|
{
|
||||||
cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
|
cl.cshifts[CSHIFT_BONUS].destcolor[0] = atof(Cmd_Argv(1))*255;
|
||||||
cl.cshifts[CSHIFT_BONUS].percent = 50;
|
cl.cshifts[CSHIFT_BONUS].destcolor[1] = atof(Cmd_Argv(2))*255;
|
||||||
|
cl.cshifts[CSHIFT_BONUS].destcolor[2] = atof(Cmd_Argv(3))*255;
|
||||||
|
cl.cshifts[CSHIFT_BONUS].percent = atof(Cmd_Argv(4))*255;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
|
||||||
|
cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
|
||||||
|
cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
|
||||||
|
cl.cshifts[CSHIFT_BONUS].percent = 50;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -533,16 +544,19 @@ void V_PolyBlend (void)
|
||||||
|
|
||||||
GL_DisableMultitexture();
|
GL_DisableMultitexture();
|
||||||
|
|
||||||
glDisable (GL_ALPHA_TEST);
|
|
||||||
glDisable (GL_TEXTURE_2D);
|
glDisable (GL_TEXTURE_2D);
|
||||||
glDisable (GL_DEPTH_TEST);
|
glDisable (GL_DEPTH_TEST);
|
||||||
glEnable (GL_BLEND);
|
glEnable (GL_BLEND);
|
||||||
|
if (premul_hud)
|
||||||
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
else
|
||||||
|
glDisable (GL_ALPHA_TEST);
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity ();
|
glLoadIdentity ();
|
||||||
glOrtho (0, 1, 1, 0, -99999, 99999);
|
glOrtho (0, 1, 1, 0, -99999, 99999);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity ();
|
glLoadIdentity ();
|
||||||
|
|
||||||
glColor4fv (v_blend);
|
glColor4fv (v_blend);
|
||||||
|
|
||||||
|
@ -553,10 +567,15 @@ void V_PolyBlend (void)
|
||||||
glVertex2f (0, 1);
|
glVertex2f (0, 1);
|
||||||
glEnd ();
|
glEnd ();
|
||||||
|
|
||||||
glDisable (GL_BLEND);
|
|
||||||
glEnable (GL_DEPTH_TEST);
|
glEnable (GL_DEPTH_TEST);
|
||||||
glEnable (GL_TEXTURE_2D);
|
glEnable (GL_TEXTURE_2D);
|
||||||
glEnable (GL_ALPHA_TEST);
|
if (premul_hud)
|
||||||
|
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glDisable (GL_BLEND);
|
||||||
|
glEnable (GL_ALPHA_TEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -642,7 +661,7 @@ void V_BoundOffsets (void)
|
||||||
{
|
{
|
||||||
entity_t *ent;
|
entity_t *ent;
|
||||||
|
|
||||||
ent = &cl_entities[cl.viewentity];
|
ent = &cl.entities[cl.viewentity];
|
||||||
|
|
||||||
// absolutely bound refresh reletive to entity clipping hull
|
// absolutely bound refresh reletive to entity clipping hull
|
||||||
// so the view can never be inside a solid wall
|
// so the view can never be inside a solid wall
|
||||||
|
@ -687,7 +706,7 @@ void V_CalcViewRoll (void)
|
||||||
{
|
{
|
||||||
float side;
|
float side;
|
||||||
|
|
||||||
side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity);
|
side = V_CalcRoll (cl.entities[cl.viewentity].angles, cl.velocity);
|
||||||
r_refdef.viewangles[ROLL] += side;
|
r_refdef.viewangles[ROLL] += side;
|
||||||
|
|
||||||
if (v_dmg_time > 0)
|
if (v_dmg_time > 0)
|
||||||
|
@ -716,7 +735,7 @@ void V_CalcIntermissionRefdef (void)
|
||||||
float old;
|
float old;
|
||||||
|
|
||||||
// ent is the player model (visible when out of body)
|
// ent is the player model (visible when out of body)
|
||||||
ent = &cl_entities[cl.viewentity];
|
ent = &cl.entities[cl.viewentity];
|
||||||
// view is the weapon model (only visible from inside body)
|
// view is the weapon model (only visible from inside body)
|
||||||
view = &cl.viewent;
|
view = &cl.viewent;
|
||||||
|
|
||||||
|
@ -750,7 +769,7 @@ void V_CalcRefdef (void)
|
||||||
V_DriftPitch ();
|
V_DriftPitch ();
|
||||||
|
|
||||||
// ent is the player model (visible when out of body)
|
// ent is the player model (visible when out of body)
|
||||||
ent = &cl_entities[cl.viewentity];
|
ent = &cl.entities[cl.viewentity];
|
||||||
// view is the weapon model (only visible from inside body)
|
// view is the weapon model (only visible from inside body)
|
||||||
view = &cl.viewent;
|
view = &cl.viewent;
|
||||||
|
|
||||||
|
@ -764,7 +783,7 @@ void V_CalcRefdef (void)
|
||||||
|
|
||||||
// refresh position
|
// refresh position
|
||||||
VectorCopy (ent->origin, r_refdef.vieworg);
|
VectorCopy (ent->origin, r_refdef.vieworg);
|
||||||
r_refdef.vieworg[2] += cl.viewheight + bob;
|
r_refdef.vieworg[2] += cl.stats[STAT_VIEWHEIGHT] + bob;
|
||||||
|
|
||||||
// never let it sit exactly on a node line, because a water plane can
|
// never let it sit exactly on a node line, because a water plane can
|
||||||
// dissapear when viewed with the eye exactly on it.
|
// dissapear when viewed with the eye exactly on it.
|
||||||
|
@ -796,7 +815,7 @@ void V_CalcRefdef (void)
|
||||||
CalcGunAngle ();
|
CalcGunAngle ();
|
||||||
|
|
||||||
VectorCopy (ent->origin, view->origin);
|
VectorCopy (ent->origin, view->origin);
|
||||||
view->origin[2] += cl.viewheight;
|
view->origin[2] += cl.stats[STAT_VIEWHEIGHT];
|
||||||
|
|
||||||
for (i=0 ; i<3 ; i++)
|
for (i=0 ; i<3 ; i++)
|
||||||
view->origin[i] += forward[i]*bob*0.4;
|
view->origin[i] += forward[i]*bob*0.4;
|
||||||
|
|
|
@ -125,7 +125,6 @@ lumpinfo_t *W_GetLumpinfo (const char *name)
|
||||||
return lump_p;
|
return lump_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
Con_SafePrintf ("W_GetLumpinfo: %s not found\n", name); //johnfitz -- was Sys_Error
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +134,11 @@ void *W_GetLumpName (const char *name)
|
||||||
|
|
||||||
lump = W_GetLumpinfo (name);
|
lump = W_GetLumpinfo (name);
|
||||||
|
|
||||||
if (!lump) return NULL; //johnfitz
|
if (!lump)
|
||||||
|
{
|
||||||
|
Con_SafePrintf ("W_GetLumpName: %s not found\n", name); //johnfitz -- was Sys_Error
|
||||||
|
return NULL; //johnfitz
|
||||||
|
}
|
||||||
|
|
||||||
return (void *)(wad_base + lump->filepos);
|
return (void *)(wad_base + lump->filepos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -601,6 +601,9 @@ LINE TESTING IN HULLS
|
||||||
==================
|
==================
|
||||||
SV_RecursiveHullCheck
|
SV_RecursiveHullCheck
|
||||||
|
|
||||||
|
Spike -- note that the pointcontents in this function are completely redundant.
|
||||||
|
This function should instead return the state of the contents of the mid position.
|
||||||
|
This would avoid all redundant recursion.
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
|
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
|
||||||
|
@ -818,6 +821,16 @@ void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip )
|
||||||
if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])
|
if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])
|
||||||
continue; // points never interact
|
continue; // points never interact
|
||||||
|
|
||||||
|
if (pr_checkextension.value)
|
||||||
|
{
|
||||||
|
//corpses are nonsolid to slidebox
|
||||||
|
if (clip->passedict->v.solid == SOLID_SLIDEBOX && touch->v.solid == SOLID_EXT_CORPSE)
|
||||||
|
continue;
|
||||||
|
//corpses ignore slidebox or corpses
|
||||||
|
if (clip->passedict->v.solid == SOLID_EXT_CORPSE && (touch->v.solid == SOLID_SLIDEBOX || touch->v.solid == SOLID_EXT_CORPSE))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// might intersect, so do an exact clip
|
// might intersect, so do an exact clip
|
||||||
if (clip->trace.allsolid)
|
if (clip->trace.allsolid)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -373,6 +373,10 @@
|
||||||
RelativePath="..\..\Quake\common.c"
|
RelativePath="..\..\Quake\common.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Quake\fs_zip.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Quake\console.c"
|
RelativePath="..\..\Quake\console.c"
|
||||||
>
|
>
|
||||||
|
@ -501,6 +505,10 @@
|
||||||
RelativePath="..\..\Quake\pr_cmds.c"
|
RelativePath="..\..\Quake\pr_cmds.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Quake\pr_ext.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Quake\pr_edict.c"
|
RelativePath="..\..\Quake\pr_edict.c"
|
||||||
>
|
>
|
||||||
|
@ -521,6 +529,10 @@
|
||||||
RelativePath="..\..\Quake\r_part.c"
|
RelativePath="..\..\Quake\r_part.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Quake\r_part_fte.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Quake\r_sprite.c"
|
RelativePath="..\..\Quake\r_sprite.c"
|
||||||
>
|
>
|
||||||
|
@ -537,6 +549,10 @@
|
||||||
RelativePath="..\..\Quake\snd_codec.c"
|
RelativePath="..\..\Quake\snd_codec.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Quake\snd_voip.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\Quake\snd_dma.c"
|
RelativePath="..\..\Quake\snd_dma.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -633,6 +633,22 @@
|
||||||
RelativePath="..\..\Quake\zone.c"
|
RelativePath="..\..\Quake\zone.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Quake\fs_zip.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Quake\snd_voip.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Quake\pr_ext.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\Quake\r_part_fte.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\SDL\main\SDL_win32_main.c"
|
RelativePath="..\SDL\main\SDL_win32_main.c"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue