mirror of
https://github.com/libretro/libretro-tyrquake.git
synced 2024-11-22 23:50:00 +00:00
Import v0.47 sources
This commit is contained in:
commit
130e22195a
892
Makefile
Normal file
892
Makefile
Normal file
@ -0,0 +1,892 @@
|
||||
#
|
||||
# A Makefile to run under MinGW on Win32
|
||||
#
|
||||
# Pretty crappy, but you can build all the targets if you clean in
|
||||
# between. It's needed because various -DXXX flags change the object files and
|
||||
# I'm still working on doing it properly... but slowly.
|
||||
#
|
||||
|
||||
TYR_VERSION_MAJOR = 0
|
||||
TYR_VERSION_MINOR = 47
|
||||
TYR_VERSION_BUILD =
|
||||
|
||||
TYR_VERSION = $(TYR_VERSION_MAJOR).$(TYR_VERSION_MINOR)$(TYR_VERSION_BUILD)
|
||||
|
||||
# ============================================================================
|
||||
# Choose the target here: (Yes, I know it sucks).
|
||||
# ============================================================================
|
||||
|
||||
TARGET_APP = NQ
|
||||
#TARGET_APP = QW
|
||||
#TARGET_APP = QWSV
|
||||
|
||||
#TARGET_RENDER = SW
|
||||
TARGET_RENDER = GL
|
||||
|
||||
#TARGET_OS = WIN32
|
||||
TARGET_OS = LINUX
|
||||
|
||||
#DEBUG=y # Compile with debug info
|
||||
#NO_X86_ASM=y # Compile with no x86 asm
|
||||
|
||||
# ============================================================================
|
||||
|
||||
# EXPORT ALL VARIABLES
|
||||
export
|
||||
|
||||
.PHONY: default clean \
|
||||
nq-w32-sw-objs nq-w32-gl-objs qw-w32-sw-objs qw-w32-gl-objs \
|
||||
qwsv-w32-objs \
|
||||
nq-linux-sw-objs nq-linux-gl-objs qw-linux-sw-objs qw-linux-gl-objs \
|
||||
qwsv-linux-objs
|
||||
|
||||
# ============================================================================
|
||||
# Helper functions
|
||||
# ============================================================================
|
||||
|
||||
check_gcc = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
|
||||
|
||||
# ============================================================================
|
||||
|
||||
# FIXME - how to detect build env reliably...?
|
||||
ifeq ($(OSTYPE),msys)
|
||||
TOPDIR := $(shell pwd -W)
|
||||
else
|
||||
TOPDIR := $(shell pwd)
|
||||
endif
|
||||
|
||||
# ----------------------------
|
||||
# The two project directories
|
||||
# ----------------------------
|
||||
|
||||
NQ_DIR = NQ
|
||||
QW_DIR = QW
|
||||
|
||||
# ----------------------------
|
||||
# Include dirs compiler flags
|
||||
# ----------------------------
|
||||
DX_INC = $(TOPDIR)/dxsdk/sdk/inc
|
||||
ST_INC = $(TOPDIR)/scitech/include
|
||||
|
||||
WIN32_SW_INC = $(DX_INC) $(ST_INC)
|
||||
WIN32_GL_INC = $(DX_INC)
|
||||
|
||||
QWSV_INC = $(TOPDIR)/$(QW_DIR)/server $(TOPDIR)/$(QW_DIR)/client
|
||||
|
||||
WIN32_SW_IFLAGS := -idirafter $(DX_INC)
|
||||
WIN32_SW_IFLAGS += -idirafter $(ST_INC)
|
||||
WIN32_SW_IFLAGS += -I$(TOPDIR)/include
|
||||
|
||||
WIN32_GL_IFLAGS := -idirafter $(DX_INC)
|
||||
WIN32_GL_IFLAGS += -I$(TOPDIR)/include
|
||||
|
||||
QWSV_WIN32_IFLAGS = $(patsubst %,-idirafter %,$(QWSV_INC)) -I$(TOPDIR)/include
|
||||
QWSV_LINUX_IFLAGS = $(patsubst %,-idirafter %,$(QWSV_INC)) -I$(TOPDIR)/include
|
||||
|
||||
# ------------------------------
|
||||
# define flags
|
||||
# ------------------------------
|
||||
DFLAGS := -DTYR_VERSION=$(TYR_VERSION)
|
||||
|
||||
# App specific hacks
|
||||
ifeq ($(TARGET_APP),NQ)
|
||||
DFLAGS += -DNQ_HACK
|
||||
endif
|
||||
ifeq ($(TARGET_APP),QW)
|
||||
DFLAGS += -DQW_HACK
|
||||
endif
|
||||
ifeq ($(TARGET_APP),QWSV)
|
||||
DFLAGS += -DQW_HACK -DSERVERONLY
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_RENDER),GL)
|
||||
DFLAGS += -DGLQUAKE
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_OS),WIN32)
|
||||
DFLAGS += -DWIN32 -D_WIN32
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
DFLAGS += -DDEBUG
|
||||
else
|
||||
DFLAGS += -DNDEBUG
|
||||
endif
|
||||
|
||||
ifdef NO_X86_ASM
|
||||
DFLAGS += -U__i386__
|
||||
endif
|
||||
|
||||
NQ_LINUX_SW_DFLAGS = $(DFLAGS) -DX11 -DELF -I$(TOPDIR)/include
|
||||
QW_LINUX_SW_DFLAGS = $(DFLAGS) -DX11 -DELF -I$(TOPDIR)/include
|
||||
NQ_LINUX_GL_DFLAGS = $(DFLAGS) -DX11 -DELF -I$(TOPDIR)/include
|
||||
QW_LINUX_GL_DFLAGS = $(DFLAGS) -DX11 -DELF -DGL_EXT_SHARED -I$(TOPDIR)/include
|
||||
|
||||
# -------------------------
|
||||
# Set up the various FLAGS
|
||||
# -------------------------
|
||||
|
||||
# NQ - Normal Quake
|
||||
ifeq ($(TARGET_APP),NQ)
|
||||
ifeq ($(TARGET_RENDER),SW)
|
||||
ifeq ($(TARGET_OS),WIN32)
|
||||
CPPFLAGS = $(DFLAGS) $(WIN32_SW_IFLAGS) -I$(TOPDIR)/NQ
|
||||
endif
|
||||
ifeq ($(TARGET_OS),LINUX)
|
||||
CPPFLAGS = $(NQ_LINUX_SW_DFLAGS) -I$(TOPDIR)/NQ
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_RENDER),GL)
|
||||
ifeq ($(TARGET_OS),WIN32)
|
||||
CPPFLAGS = $(DFLAGS) $(WIN32_GL_IFLAGS) -I$(TOPDIR)/NQ
|
||||
endif
|
||||
ifeq ($(TARGET_OS),LINUX)
|
||||
CPPFLAGS = $(NQ_LINUX_GL_DFLAGS) $(NQ_LINUX_GL_IFLAGS) -I$(TOPDIR)/NQ
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# QW - QuakeWorld Client
|
||||
ifeq ($(TARGET_APP),QW)
|
||||
ifeq ($(TARGET_RENDER),SW)
|
||||
ifeq ($(TARGET_OS),WIN32)
|
||||
CPPFLAGS = $(DFLAGS) $(WIN32_SW_IFLAGS) -I$(TOPDIR)/$(QW_DIR)/client -I$(TOPDIR)/$(QW_DIR)/common
|
||||
endif
|
||||
ifeq ($(TARGET_OS),LINUX)
|
||||
CPPFLAGS = $(QW_LINUX_SW_DFLAGS) -I$(TOPDIR)/$(QW_DIR)/client -I$(TOPDIR)/$(QW_DIR)/common
|
||||
endif
|
||||
endif
|
||||
ifeq ($(TARGET_RENDER),GL)
|
||||
ifeq ($(TARGET_OS),WIN32)
|
||||
CPPFLAGS = $(DFLAGS) $(WIN32_GL_IFLAGS) -I$(TOPDIR)/$(QW_DIR)/client -I$(TOPDIR)/$(QW_DIR)/common
|
||||
endif
|
||||
ifeq ($(TARGET_OS),LINUX)
|
||||
CPPFLAGS = $(QW_LINUX_GL_DFLAGS) $(QW_LINUX_GL_IFLAGS) -I$(TOPDIR)/$(QW_DIR)/client -I$(TOPDIR)/$(QW_DIR)/common
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# QWSV - QuakeWorld Server
|
||||
ifeq ($(TARGET_APP),QWSV)
|
||||
ifeq ($(TARGET_OS),WIN32)
|
||||
CPPFLAGS = $(DFLAGS) $(QWSV_WIN32_IFLAGS)
|
||||
endif
|
||||
ifeq ($(TARGET_OS),LINUX)
|
||||
CPPFLAGS = $(DFLAGS) $(QWSV_LINUX_IFLAGS)
|
||||
endif
|
||||
endif
|
||||
|
||||
# ------------------------------------------------------
|
||||
# Define the default target based on TARGET_* variables
|
||||
# ------------------------------------------------------
|
||||
DT_PREFIX =tyr-
|
||||
ifeq ($(TARGET_RENDER),GL)
|
||||
DT_RENDER =gl
|
||||
else
|
||||
DT_RENDER =
|
||||
endif
|
||||
ifeq ($(TARGET_APP),NQ)
|
||||
DT_APP =quake
|
||||
endif
|
||||
ifeq ($(TARGET_APP),QW)
|
||||
DT_APP =qwcl
|
||||
endif
|
||||
ifeq ($(TARGET_APP),QWSV)
|
||||
DT_APP =qwsv
|
||||
endif
|
||||
ifeq ($(TARGET_OS),WIN32)
|
||||
DT_EXT =.exe
|
||||
else
|
||||
DT_EXT =
|
||||
endif
|
||||
|
||||
DEFAULT_TARGET = $(DT_PREFIX)$(DT_RENDER)$(DT_APP)$(DT_EXT)
|
||||
|
||||
# --------------
|
||||
# Library stuff
|
||||
# --------------
|
||||
WIN_LIBDIR = C:/mingw-1.1/lib
|
||||
NQ_ST_LIBDIR = scitech/lib/win32/vc
|
||||
QW_ST_LIBDIR = scitech/lib/win32/vc
|
||||
|
||||
NQ_W32_COMMON_LIBS = wsock32 winmm dxguid
|
||||
NQ_W32_SW_LIBS = mgllt ddraw
|
||||
NQ_W32_GL_LIBS = opengl32 comctl32
|
||||
|
||||
LINUX_X11_LIBDIR = /usr/X11R6/lib
|
||||
NQ_LINUX_COMMON_LIBS = m X11 Xext Xxf86dga Xxf86vm
|
||||
NQ_LINUX_GL_LIBS = GL
|
||||
|
||||
NQ_W32_SW_LFLAGS = -mwindows $(patsubst %,-l%,$(NQ_W32_SW_LIBS) $(NQ_W32_COMMON_LIBS))
|
||||
NQ_W32_GL_LFLAGS = -mwindows $(patsubst %,-l%,$(NQ_W32_GL_LIBS) $(NQ_W32_COMMON_LIBS))
|
||||
NQ_LINUX_SW_LFLAGS = $(patsubst %,-l%,$(NQ_LINUX_COMMON_LIBS))
|
||||
NQ_LINUX_GL_LFLAGS = $(patsubst %,-l%,$(NQ_LINUX_COMMON_LIBS) $(NQ_LINUX_GL_LIBS))
|
||||
|
||||
# ---------------------------------------
|
||||
# Define some build variables
|
||||
# ---------------------------------------
|
||||
|
||||
# Try to use a more recent GCC if available (my Debian system has several)
|
||||
ifneq ($(shell which gcc-3.5),)
|
||||
CC = gcc-3.5
|
||||
else
|
||||
ifneq ($(shell which gcc-3.4),)
|
||||
CC = gcc-3.4
|
||||
else
|
||||
CC = gcc
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS := -Wall -Wno-trigraphs
|
||||
|
||||
# Library headers on the Windows side give warnings
|
||||
ifeq ($(TARGET_OS),LINUX)
|
||||
CFLAGS += -Werror
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS += -g
|
||||
STRIP_CMD = @echo "** Debug build - not stripping"
|
||||
else
|
||||
# Note that "-fomit-frame-pointer" seems to screw some things up
|
||||
# (at least on MinGW)
|
||||
CFLAGS += -O2
|
||||
CFLAGS += $(call check_gcc,-fweb,)
|
||||
CFLAGS += $(call check_gcc,-frename-registers,)
|
||||
CFLAGS += $(call check_gcc,-mtune=i686,-mcpu=i686)
|
||||
STRIP_CMD = strip
|
||||
endif
|
||||
|
||||
# -------------------------------------
|
||||
# Got to build something by default...
|
||||
# -------------------------------------
|
||||
|
||||
default: $(DEFAULT_TARGET)
|
||||
|
||||
# ---------------------------
|
||||
# Tweak the implicit ruleset
|
||||
# ---------------------------
|
||||
|
||||
%.o: %.S
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $^
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $^
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Normal Quake (NQ)
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# Objects common to all versions of NQ, sources are c code
|
||||
NQ_COMMON_C_OBJS = \
|
||||
chase.o \
|
||||
cl_demo.o \
|
||||
cl_input.o \
|
||||
cl_main.o \
|
||||
cl_parse.o \
|
||||
cl_tent.o \
|
||||
cmd.o \
|
||||
common.o \
|
||||
console.o \
|
||||
crc.o \
|
||||
cvar.o \
|
||||
host.o \
|
||||
host_cmd.o \
|
||||
keys.o \
|
||||
mathlib.o \
|
||||
menu.o \
|
||||
net_dgrm.o \
|
||||
net_loop.o \
|
||||
net_main.o \
|
||||
net_vcr.o \
|
||||
pr_cmds.o \
|
||||
pr_edict.o \
|
||||
pr_exec.o \
|
||||
r_part.o \
|
||||
\
|
||||
rb_tree.o \
|
||||
\
|
||||
sbar.o \
|
||||
\
|
||||
shell.o \
|
||||
\
|
||||
snd_dma.o \
|
||||
snd_mem.o \
|
||||
snd_mix.o \
|
||||
sv_main.o \
|
||||
sv_move.o \
|
||||
sv_phys.o \
|
||||
sv_user.o \
|
||||
view.o \
|
||||
wad.o \
|
||||
world.o \
|
||||
zone.o
|
||||
|
||||
NQ_COMMON_ASM_OBJS = \
|
||||
math.o \
|
||||
snd_mixa.o \
|
||||
worlda.o
|
||||
|
||||
# Used in both SW and GL versions of NQ on the Win32 platform
|
||||
NQ_W32_C_OBJS = \
|
||||
cd_win.o \
|
||||
conproc.o \
|
||||
in_win.o \
|
||||
net_win.o \
|
||||
net_wins.o \
|
||||
net_wipx.o \
|
||||
snd_win.o \
|
||||
sys_win.o
|
||||
|
||||
NQ_W32_ASM_OBJS = \
|
||||
sys_wina.o
|
||||
|
||||
# Used in both SW and GL versions on NQ on the Linux platform
|
||||
NQ_LINUX_C_OBJS = \
|
||||
cd_linux.o \
|
||||
net_udp.o \
|
||||
net_bsd.o \
|
||||
snd_linux.o \
|
||||
sys_linux.o \
|
||||
x11_core.o \
|
||||
in_x11.o
|
||||
|
||||
NQ_LINUX_ASM_OBJS = \
|
||||
sys_dosa.o
|
||||
|
||||
# Objects only used in software rendering versions of NQ
|
||||
NQ_SW_C_OBJS = \
|
||||
d_edge.o \
|
||||
d_fill.o \
|
||||
d_init.o \
|
||||
d_modech.o \
|
||||
d_part.o \
|
||||
d_polyse.o \
|
||||
d_scan.o \
|
||||
d_sky.o \
|
||||
d_sprite.o \
|
||||
d_surf.o \
|
||||
d_vars.o \
|
||||
d_zpoint.o \
|
||||
draw.o \
|
||||
model.o \
|
||||
r_aclip.o \
|
||||
r_alias.o \
|
||||
r_bsp.o \
|
||||
r_draw.o \
|
||||
r_edge.o \
|
||||
r_efrag.o \
|
||||
r_light.o \
|
||||
r_main.o \
|
||||
r_misc.o \
|
||||
r_sky.o \
|
||||
r_sprite.o \
|
||||
r_surf.o \
|
||||
r_vars.o \
|
||||
screen.o
|
||||
|
||||
NQ_SW_ASM_OBJS = \
|
||||
d_draw.o \
|
||||
d_draw16.o \
|
||||
d_parta.o \
|
||||
d_polysa.o \
|
||||
d_scana.o \
|
||||
d_spr8.o \
|
||||
d_varsa.o \
|
||||
r_aclipa.o \
|
||||
r_aliasa.o \
|
||||
r_drawa.o \
|
||||
r_edgea.o \
|
||||
r_varsa.o \
|
||||
surf16.o \
|
||||
surf8.o
|
||||
|
||||
# Objects only used in software rendering versions of NQ on the Win32 Platform
|
||||
NQ_W32_SW_C_OBJS = \
|
||||
vid_win.o
|
||||
|
||||
NQ_W32_SW_ASM_OBJS = \
|
||||
dosasm.o
|
||||
|
||||
# Objects only used in software rendering versions of NQ on the Linux Platform
|
||||
NQ_LINUX_SW_C_OBJS = \
|
||||
vid_x.o
|
||||
|
||||
NQ_LINUX_SW_AMS_OBJS =
|
||||
|
||||
# Objects only used in OpenGL rendering versions of NQ
|
||||
NQ_GL_C_OBJS = \
|
||||
drawhulls.o \
|
||||
gl_draw.o \
|
||||
gl_mesh.o \
|
||||
gl_model.o \
|
||||
gl_refrag.o \
|
||||
gl_rlight.o \
|
||||
gl_rmain.o \
|
||||
gl_rmisc.o \
|
||||
gl_rsurf.o \
|
||||
gl_screen.o \
|
||||
gl_warp.o
|
||||
|
||||
NQ_GL_ASM_OBJS =
|
||||
|
||||
# Objects only used in OpenGL rendering versions of NQ on the Win32 Platform
|
||||
NQ_W32_GL_C_OBJS = \
|
||||
gl_vidnt.o
|
||||
|
||||
NQ_W32_GL_ASM_OBJS =
|
||||
|
||||
# Objects only used in OpenGL rendering versions of NQ on the Linux Platform
|
||||
NQ_LINUX_GL_C_OBJS = \
|
||||
gl_vidlinuxglx.o
|
||||
|
||||
NQ_LINUX_GL_ASM_OBJS =
|
||||
|
||||
# Misc objects that don't seem to get used...
|
||||
NQ_OTHER_ASM_OBJS = \
|
||||
d_copy.o \
|
||||
sys_dosa.o
|
||||
|
||||
NQ_OTHER_C_OBJS =
|
||||
|
||||
# =========================================================================== #
|
||||
|
||||
# Build the list of object files for each particular target
|
||||
# (*sigh* - something has to be done about this makefile...)
|
||||
|
||||
NQ_W32_SW_OBJS := $(NQ_COMMON_C_OBJS)
|
||||
NQ_W32_SW_OBJS += $(NQ_SW_C_OBJS)
|
||||
NQ_W32_SW_OBJS += $(NQ_W32_C_OBJS)
|
||||
NQ_W32_SW_OBJS += $(NQ_W32_SW_C_OBJS)
|
||||
NQ_W32_SW_OBJS += winquake.res
|
||||
ifdef NO_X86_ASM
|
||||
NQ_W32_SW_OBJS += nonintel.o
|
||||
else
|
||||
NQ_W32_SW_OBJS += $(NQ_COMMON_ASM_OBJS)
|
||||
NQ_W32_SW_OBJS += $(NQ_SW_ASM_OBJS)
|
||||
NQ_W32_SW_OBJS += $(NQ_W32_ASM_OBJS)
|
||||
NQ_W32_SW_OBJS += $(NQ_W32_SW_ASM_OBJS)
|
||||
endif
|
||||
|
||||
NQ_W32_GL_OBJS := $(NQ_COMMON_C_OBJS)
|
||||
NQ_W32_GL_OBJS += $(NQ_GL_C_OBJS)
|
||||
NQ_W32_GL_OBJS += $(NQ_W32_C_OBJS)
|
||||
NQ_W32_GL_OBJS += $(NQ_W32_GL_C_OBJS)
|
||||
NQ_W32_GL_OBJS += winquake.res
|
||||
ifndef NO_X86_ASM
|
||||
NQ_W32_GL_OBJS += $(NQ_COMMON_ASM_OBJS)
|
||||
NQ_W32_GL_OBJS += $(NQ_GL_ASM_OBJS)
|
||||
NQ_W32_GL_OBJS += $(NQ_W32_ASM_OBJS)
|
||||
NQ_W32_GL_OBJS += $(NQ_W32_GL_ASM_OBJS)
|
||||
endif
|
||||
|
||||
NQ_LINUX_SW_OBJS := $(NQ_COMMON_C_OBJS)
|
||||
NQ_LINUX_SW_OBJS += $(NQ_SW_C_OBJS)
|
||||
NQ_LINUX_SW_OBJS += $(NQ_LINUX_C_OBJS)
|
||||
NQ_LINUX_SW_OBJS += $(NQ_LINUX_SW_C_OBJS)
|
||||
ifdef NO_X86_ASM
|
||||
NQ_LINUX_SW_OBJS += nonintel.o
|
||||
else
|
||||
NQ_LINUX_SW_OBJS += $(NQ_COMMON_ASM_OBJS)
|
||||
NQ_LINUX_SW_OBJS += $(NQ_SW_ASM_OBJS)
|
||||
NQ_LINUX_SW_OBJS += $(NQ_LINUX_ASM_OBJS)
|
||||
NQ_LINUX_SW_OBJS += $(NQ_LINUX_SW_ASM_OBJS)
|
||||
endif
|
||||
|
||||
NQ_LINUX_GL_OBJS := $(NQ_COMMON_C_OBJS)
|
||||
NQ_LINUX_GL_OBJS += $(NQ_GL_C_OBJS)
|
||||
NQ_LINUX_GL_OBJS += $(NQ_LINUX_C_OBJS)
|
||||
NQ_LINUX_GL_OBJS += $(NQ_LINUX_GL_C_OBJS)
|
||||
ifndef NO_X86_ASM
|
||||
NQ_LINUX_GL_OBJS += $(NQ_COMMON_ASM_OBJS)
|
||||
NQ_LINUX_GL_OBJS += $(NQ_GL_ASM_OBJS)
|
||||
NQ_LINUX_GL_OBJS += $(NQ_LINUX_ASM_OBJS)
|
||||
NQ_LINUX_GL_OBJS += $(NQ_LINUX_GL_ASM_OBJS)
|
||||
endif
|
||||
|
||||
# ------------------------
|
||||
# Now, the build rules...
|
||||
# ------------------------
|
||||
|
||||
# Win32
|
||||
nq-w32-sw-objs:
|
||||
$(MAKE) -C $(NQ_DIR) quake-sw-win32
|
||||
|
||||
nq-w32-gl-objs:
|
||||
$(MAKE) -C $(NQ_DIR) quake-gl-win32
|
||||
|
||||
tyr-quake.exe: nq-w32-sw-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $(patsubst %,$(NQ_DIR)/%,$(NQ_W32_SW_OBJS)) -L$(WIN_LIBDIR) -L$(NQ_ST_LIBDIR) $(NQ_W32_SW_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
tyr-glquake.exe: nq-w32-gl-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $(patsubst %,$(NQ_DIR)/%,$(NQ_W32_GL_OBJS)) -L$(WIN_LIBDIR) -L$(NQ_ST_LIBDIR) $(NQ_W32_GL_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
# Linux
|
||||
nq-linux-sw-objs:
|
||||
$(MAKE) -C $(NQ_DIR) quake-sw-linux
|
||||
|
||||
nq-linux-gl-objs:
|
||||
$(MAKE) -C $(NQ_DIR) quake-gl-linux
|
||||
|
||||
tyr-quake: nq-linux-sw-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o tyr-quake $(patsubst %,$(NQ_DIR)/%,$(NQ_LINUX_SW_OBJS)) -L$(LINUX_X11_LIBDIR) $(NQ_LINUX_SW_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
tyr-glquake: nq-linux-gl-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o tyr-glquake $(patsubst %,$(NQ_DIR)/%,$(NQ_LINUX_GL_OBJS)) -L$(LINUX_X11_LIBDIR) $(NQ_LINUX_GL_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# QuakeWorld (QW) - Client
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
QW_SV_SHARED_C_OBJS = \
|
||||
cmd.o \
|
||||
common.o \
|
||||
crc.o \
|
||||
cvar.o \
|
||||
mathlib.o \
|
||||
md4.o \
|
||||
net_chan.o \
|
||||
pmove.o \
|
||||
pmovetst.o \
|
||||
rb_tree.o \
|
||||
shell.o \
|
||||
zone.o
|
||||
|
||||
QW_COMMON_C_OBJS = \
|
||||
$(QW_SV_SHARED_C_OBJS) \
|
||||
cl_cam.o \
|
||||
cl_demo.o \
|
||||
cl_ents.o \
|
||||
cl_input.o \
|
||||
cl_main.o \
|
||||
cl_parse.o \
|
||||
cl_pred.o \
|
||||
cl_tent.o \
|
||||
console.o \
|
||||
keys.o \
|
||||
menu.o \
|
||||
r_part.o \
|
||||
sbar.o \
|
||||
skin.o \
|
||||
snd_dma.o \
|
||||
snd_mem.o \
|
||||
snd_mix.o \
|
||||
view.o \
|
||||
wad.o
|
||||
|
||||
QW_COMMON_ASM_OBJS = \
|
||||
math.o \
|
||||
snd_mixa.o
|
||||
|
||||
QW_W32_C_OBJS = \
|
||||
cd_win.o \
|
||||
in_win.o \
|
||||
net_wins.o \
|
||||
snd_win.o \
|
||||
sys_win.o
|
||||
|
||||
QW_W32_ASM_OBJS = \
|
||||
sys_wina.o
|
||||
|
||||
QW_LINUX_SV_SHARED_C_OBJS = \
|
||||
net_udp.o
|
||||
|
||||
QW_LINUX_C_OBJS = \
|
||||
$(QW_LINUX_SV_SHARED_C_OBJS) \
|
||||
cd_linux.o \
|
||||
snd_linux.o \
|
||||
sys_linux.o \
|
||||
in_x11.o \
|
||||
x11_core.o
|
||||
|
||||
QW_LINUX_ASM_OBJS = \
|
||||
sys_dosa.o
|
||||
|
||||
QW_SW_C_OBJS = \
|
||||
d_edge.o \
|
||||
d_fill.o \
|
||||
d_init.o \
|
||||
d_modech.o \
|
||||
d_part.o \
|
||||
d_polyse.o \
|
||||
d_scan.o \
|
||||
d_sky.o \
|
||||
d_sprite.o \
|
||||
d_surf.o \
|
||||
d_vars.o \
|
||||
d_zpoint.o \
|
||||
draw.o \
|
||||
model.o \
|
||||
r_aclip.o \
|
||||
r_alias.o \
|
||||
r_bsp.o \
|
||||
r_draw.o \
|
||||
r_edge.o \
|
||||
r_efrag.o \
|
||||
r_light.o \
|
||||
r_main.o \
|
||||
r_misc.o \
|
||||
r_sky.o \
|
||||
r_sprite.o \
|
||||
r_surf.o \
|
||||
r_vars.o \
|
||||
screen.o
|
||||
|
||||
QW_SW_ASM_OBJS = \
|
||||
d_draw.o \
|
||||
d_draw16.o \
|
||||
d_parta.o \
|
||||
d_polysa.o \
|
||||
d_scana.o \
|
||||
d_spr8.o \
|
||||
d_varsa.o \
|
||||
r_aclipa.o \
|
||||
r_aliasa.o \
|
||||
r_drawa.o \
|
||||
r_edgea.o \
|
||||
r_varsa.o \
|
||||
surf16.o \
|
||||
surf8.o
|
||||
|
||||
QW_W32_SW_C_OBJS = \
|
||||
vid_win.o
|
||||
|
||||
QW_W32_SW_ASM_OBJS =
|
||||
|
||||
QW_LINUX_SW_C_OBJS = \
|
||||
vid_x.o
|
||||
|
||||
QW_LINUX_SW_ASM_OBJS =
|
||||
|
||||
QW_GL_C_OBJS = \
|
||||
drawhulls.o \
|
||||
gl_draw.o \
|
||||
gl_mesh.o \
|
||||
gl_model.o \
|
||||
gl_ngraph.o \
|
||||
gl_refrag.o \
|
||||
gl_rlight.o \
|
||||
gl_rmain.o \
|
||||
gl_rmisc.o \
|
||||
gl_rsurf.o \
|
||||
gl_screen.o \
|
||||
gl_warp.o
|
||||
|
||||
QW_GL_ASM_OBJS =
|
||||
|
||||
QW_W32_GL_C_OBJS = \
|
||||
gl_vidnt.o
|
||||
|
||||
QW_W32_GL_ASM_OBJS =
|
||||
|
||||
QW_LINUX_GL_C_OBJS = \
|
||||
gl_vidlinuxglx.o
|
||||
|
||||
QW_LINUX_GL_ASM_OBJS =
|
||||
|
||||
# ========================================================================== #
|
||||
|
||||
# Build the list of object files for each particular target
|
||||
# (*sigh* - something has to be done about this makefile...)
|
||||
|
||||
QW_W32_SW_OBJS := $(QW_COMMON_C_OBJS)
|
||||
QW_W32_SW_OBJS += $(QW_SW_C_OBJS)
|
||||
QW_W32_SW_OBJS += $(QW_W32_C_OBJS)
|
||||
QW_W32_SW_OBJS += $(QW_W32_SW_C_OBJS)
|
||||
QW_W32_SW_OBJS += winquake.res
|
||||
ifdef NO_X86_ASM
|
||||
QW_W32_SW_OBJS += nonintel.o
|
||||
else
|
||||
QW_W32_SW_OBJS += $(QW_COMMON_ASM_OBJS)
|
||||
QW_W32_SW_OBJS += $(QW_SW_ASM_OBJS)
|
||||
QW_W32_SW_OBJS += $(QW_W32_ASM_OBJS)
|
||||
QW_W32_SW_OBJS += $(QW_W32_SW_ASM_OBJS)
|
||||
endif
|
||||
|
||||
QW_W32_GL_OBJS := $(QW_COMMON_C_OBJS)
|
||||
QW_W32_GL_OBJS += $(QW_GL_C_OBJS)
|
||||
QW_W32_GL_OBJS += $(QW_W32_C_OBJS)
|
||||
QW_W32_GL_OBJS += $(QW_W32_GL_C_OBJS)
|
||||
QW_W32_GL_OBJS += winquake.res
|
||||
ifndef NO_X86_ASM
|
||||
QW_W32_GL_OBJS += $(QW_COMMON_ASM_OBJS)
|
||||
QW_W32_GL_OBJS += $(QW_GL_ASM_OBJS)
|
||||
QW_W32_GL_OBJS += $(QW_W32_ASM_OBJS)
|
||||
QW_W32_GL_OBJS += $(QW_W32_GL_ASM_OBJS)
|
||||
endif
|
||||
|
||||
QW_LINUX_SW_OBJS := $(QW_COMMON_C_OBJS)
|
||||
QW_LINUX_SW_OBJS += $(QW_SW_C_OBJS)
|
||||
QW_LINUX_SW_OBJS += $(QW_LINUX_C_OBJS)
|
||||
QW_LINUX_SW_OBJS += $(QW_LINUX_SW_C_OBJS)
|
||||
ifdef NO_X86_ASM
|
||||
QW_LINUX_SW_OBJS += nonintel.o
|
||||
else
|
||||
QW_LINUX_SW_OBJS += $(QW_COMMON_ASM_OBJS)
|
||||
QW_LINUX_SW_OBJS += $(QW_SW_ASM_OBJS)
|
||||
QW_LINUX_SW_OBJS += $(QW_LINUX_ASM_OBJS)
|
||||
QW_LINUX_SW_OBJS += $(QW_LINUX_SW_ASM_OBJS)
|
||||
endif
|
||||
|
||||
QW_LINUX_GL_OBJS := $(QW_COMMON_C_OBJS)
|
||||
QW_LINUX_GL_OBJS += $(QW_GL_C_OBJS)
|
||||
QW_LINUX_GL_OBJS += $(QW_LINUX_C_OBJS)
|
||||
QW_LINUX_GL_OBJS += $(QW_LINUX_GL_C_OBJS)
|
||||
ifndef NO_X86_ASM
|
||||
QW_LINUX_GL_OBJS += $(QW_COMMON_ASM_OBJS)
|
||||
QW_LINUX_GL_OBJS += $(QW_GL_ASM_OBJS)
|
||||
QW_LINUX_GL_OBJS += $(QW_LINUX_ASM_OBJS)
|
||||
QW_LINUX_GL_OBJS += $(QW_LINUX_GL_ASM_OBJS)
|
||||
endif
|
||||
|
||||
# ---------
|
||||
# QW Libs
|
||||
# ---------
|
||||
QW_W32_COMMON_LIBS = wsock32 dxguid winmm
|
||||
QW_W32_SW_LIBS = mgllt
|
||||
QW_W32_GL_LIBS = opengl32 comctl32
|
||||
|
||||
QW_LINUX_COMMON_LIBS = m X11 Xext Xxf86dga Xxf86vm
|
||||
QW_LINUX_GL_LIBS = GL
|
||||
|
||||
QW_W32_SW_LFLAGS = -mwindows $(patsubst %,-l%,$(QW_W32_SW_LIBS) $(QW_W32_COMMON_LIBS))
|
||||
QW_W32_GL_LFLAGS = -mwindows $(patsubst %,-l%,$(QW_W32_GL_LIBS) $(QW_W32_COMMON_LIBS))
|
||||
QW_LINUX_SW_LFLAGS = $(patsubst %,-l%,$(QW_LINUX_COMMON_LIBS))
|
||||
QW_LINUX_GL_LFLAGS = $(patsubst %,-l%,$(QW_LINUX_COMMON_LIBS) $(QW_LINUX_GL_LIBS))
|
||||
|
||||
# ---------------------
|
||||
# build rules
|
||||
# --------------------
|
||||
|
||||
# Win32
|
||||
qw-w32-sw-objs:
|
||||
$(MAKE) -C $(QW_DIR)/client qwcl-sw-win32
|
||||
|
||||
qw-w32-gl-objs:
|
||||
$(MAKE) -C $(QW_DIR)/client qwcl-gl-win32
|
||||
|
||||
tyr-qwcl.exe: qw-w32-sw-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o tyr-qwcl.exe $(patsubst %,$(QW_DIR)/client/%,$(QW_W32_SW_OBJS)) -L$(WIN_LIBDIR) -L$(QW_ST_LIBDIR) $(QW_W32_SW_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
tyr-glqwcl.exe: qw-w32-gl-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o tyr-glqwcl.exe $(patsubst %,$(QW_DIR)/client/%,$(QW_W32_GL_OBJS)) -L$(WIN_LIBDIR) $(QW_W32_GL_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
# Linux
|
||||
qw-linux-sw-objs:
|
||||
$(MAKE) -C $(QW_DIR)/client qwcl-sw-linux
|
||||
|
||||
qw-linux-gl-objs:
|
||||
$(MAKE) -C $(QW_DIR)/client qwcl-gl-linux
|
||||
|
||||
tyr-qwcl: qw-linux-sw-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o tyr-qwcl $(patsubst %,$(QW_DIR)/client/%,$(QW_LINUX_SW_OBJS)) -L$(LINUX_X11_LIBDIR) $(QW_LINUX_SW_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
tyr-glqwcl: qw-linux-gl-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o tyr-glqwcl $(patsubst %,$(QW_DIR)/client/%,$(QW_LINUX_GL_OBJS)) -L$(LINUX_X11_LIBDIR) $(QW_LINUX_GL_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
UNUSED_OBJS = cd_audio.o
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# QuakeWorld (QW) - Server
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
QWSV_SHARED_OBJS = \
|
||||
cmd.o \
|
||||
common.o \
|
||||
crc.o \
|
||||
cvar.o \
|
||||
mathlib.o \
|
||||
md4.o \
|
||||
net_chan.o \
|
||||
pmove.o \
|
||||
pmovetst.o \
|
||||
rb_tree.o \
|
||||
shell.o \
|
||||
zone.o
|
||||
|
||||
QWSV_W32_SHARED_OBJS = \
|
||||
net_wins.o
|
||||
|
||||
QWSV_LINUX_SHARED_OBJS = \
|
||||
net_udp.o
|
||||
|
||||
QWSV_ONLY_OBJS = \
|
||||
model.o \
|
||||
pr_cmds.o \
|
||||
pr_edict.o \
|
||||
pr_exec.o \
|
||||
sv_ccmds.o \
|
||||
sv_ents.o \
|
||||
sv_init.o \
|
||||
sv_main.o \
|
||||
sv_move.o \
|
||||
sv_nchan.o \
|
||||
sv_phys.o \
|
||||
sv_send.o \
|
||||
sv_user.o \
|
||||
world.o
|
||||
|
||||
QWSV_W32_ONLY_OBJS = \
|
||||
sys_win.o
|
||||
|
||||
QWSV_LINUX_ONLY_OBJS = \
|
||||
sys_unix.o
|
||||
|
||||
QWSV_W32_OBJS = \
|
||||
$(QWSV_SHARED_OBJS) \
|
||||
$(QWSV_W32_SHARED_OBJS) \
|
||||
$(QWSV_ONLY_OBJS) \
|
||||
$(QWSV_W32_ONLY_OBJS)
|
||||
|
||||
QWSV_LINUX_OBJS = \
|
||||
$(QWSV_SHARED_OBJS) \
|
||||
$(QWSV_LINUX_SHARED_OBJS) \
|
||||
$(QWSV_ONLY_OBJS) \
|
||||
$(QWSV_LINUX_ONLY_OBJS)
|
||||
|
||||
# ----------------
|
||||
# QWSV Libs
|
||||
# ----------------
|
||||
QWSV_W32_LIBS = wsock32 winmm
|
||||
QWSV_W32_LFLAGS = -mconsole $(patsubst %,-l%,$(QWSV_W32_LIBS))
|
||||
QWSV_LINUX_LIBS = m
|
||||
QWSV_LINUX_LFLAGS = $(patsubst %,-l%,$(QWSV_LINUX_LIBS))
|
||||
|
||||
# -------------
|
||||
# Build rules
|
||||
# -------------
|
||||
|
||||
# Win32
|
||||
qwsv-w32-objs:
|
||||
$(MAKE) -C $(QW_DIR)/server qwsv-win32
|
||||
|
||||
tyr-qwsv.exe: qwsv-w32-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o tyr-qwsv.exe $(patsubst %,$(QW_DIR)/server/%,$(QWSV_W32_OBJS)) -L$(WIN_LIBDIR) $(QWSV_W32_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
# Linux
|
||||
qwsv-linux-objs:
|
||||
$(MAKE) -C $(QW_DIR)/server qwsv-linux
|
||||
|
||||
tyr-qwsv: qwsv-linux-objs
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -o tyr-qwsv $(patsubst %,$(QW_DIR)/server/%,$(QWSV_LINUX_OBJS)) $(QWSV_LINUX_LFLAGS)
|
||||
$(STRIP_CMD) $@
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Very basic clean target (can't use xargs on MSYS)
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# Main clean function...
|
||||
clean:
|
||||
@rm -f $(shell find . \( \
|
||||
-name '*~' -o -name '#*#' -o -name '*.o' -o -name '*.res' \
|
||||
\) -print)
|
69
NQ/3dfx.txt
Normal file
69
NQ/3dfx.txt
Normal file
@ -0,0 +1,69 @@
|
||||
GLQuake Drivers
|
||||
|
||||
Graphics Subsystem: Voodoo Graphics or Voodoo Rush
|
||||
|
||||
Copyright ( 1997 3Dfx Interactive, Inc. )
|
||||
All Rights Reserved
|
||||
|
||||
3Dfx Interactive, Inc.
|
||||
www: www.3dfx.com
|
||||
news: news.3dfx.com
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
NOTE: GLQuake requires DirectX support DirectSound. DirectX can be
|
||||
installed from the media provided with your Voodoo Based 3D Accelerator.
|
||||
|
||||
Glide 2.31 or HIGHER runtime drivers *MUST* be installed to use this
|
||||
GLQuake driver. Please download these drivers from your board
|
||||
manufacturer OR unsupported drivers from http://www.3dfx.com
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
Release Notes for GLQuake's mini-GL driver
|
||||
|
||||
What's in the distribution?
|
||||
---------------------------
|
||||
|
||||
This distribution contains GLQuake Drivers for Voodoo Based 3D
|
||||
Accelerators. These drivers were tested on the following boards:
|
||||
|
||||
Voodoo Graphics:
|
||||
- Quantum 3D Obsidian
|
||||
- Diamond Monster 3D
|
||||
- Orchid Righteous 3D
|
||||
- Deltron Realvision Flash 3D
|
||||
- Guillemot MaxiGamer
|
||||
- Skywell Magic 3D
|
||||
|
||||
Voodoo Rush:
|
||||
- Hercules Stringray 128-3D
|
||||
- Intergraph Intense 3D Voodoo
|
||||
- Jazz Multimedia Adrenaline Rush
|
||||
|
||||
NOTE: The enclosed drivers are not meant to replace any Direct3D or
|
||||
Glide drivers provided by your Voodoo Graphics card manufacturer.
|
||||
Please obtain supported drivers from your board manufacturer.
|
||||
|
||||
OEMSR2 and NT users: Do NOT replace OPENGL32.DLL located in your
|
||||
Windows\SYSTEM directory.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- Voodoo Graphics or Voodoo Rush Based 3D Accelerator
|
||||
- Windows 95 (Windows NT is supported for Voodoo Rush)
|
||||
- A PC with a Pentium 90 or higher CPU
|
||||
- 16MB of RAM
|
||||
- 2D Video card set at 16 bit color
|
||||
|
||||
Support and Frequently Asked Questions
|
||||
--------------------------------------
|
||||
|
||||
GLQuake is currently unsupported. You may however find answers to
|
||||
questions on various Quake dedicated websites. 3Dfx provides a GLQuake
|
||||
newsgroup on news.3dfx.com (Newsgroup name is 3dfx.games.glquake ) to
|
||||
discuss GLQuake with other users. 3Dfx also provides a regularly
|
||||
updated GLQuake FAQ at: http://www.3dfx.com/game_dev/quake_faq.html
|
||||
|
||||
|
||||
Voodoo Graphics and Voodoo Rush are trademarks of 3Dfx Interactive, Inc.
|
||||
All other trademarks are the property of their respective owners.
|
34
NQ/Makefile
Normal file
34
NQ/Makefile
Normal file
@ -0,0 +1,34 @@
|
||||
# ------------
|
||||
# NQ Makefile - to be called from the main makefile
|
||||
# ------------
|
||||
|
||||
# Not quite ready for buildirs, etc.
|
||||
# More seperation required:
|
||||
# - Core engine
|
||||
# - Renderer
|
||||
# - System
|
||||
|
||||
.PHONY: default \
|
||||
quake-sw-win32 quake-gl-win32 quake-sw-linux quake-gl-linux
|
||||
|
||||
# Rules to compile stuff from the common dir...
|
||||
%.o: ../common/%.S
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $^
|
||||
|
||||
%.o: ../common/%.c
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $^
|
||||
|
||||
# Rule to make the resource file
|
||||
%.res: %.rc
|
||||
windres -i $^ -O coff -o $@
|
||||
|
||||
# Don't build anything by default
|
||||
default:
|
||||
|
||||
quake-sw-win32: $(NQ_W32_SW_OBJS)
|
||||
|
||||
quake-gl-win32: $(NQ_W32_GL_OBJS)
|
||||
|
||||
quake-sw-linux: $(NQ_LINUX_SW_OBJS)
|
||||
|
||||
quake-gl-linux: $(NQ_LINUX_GL_OBJS)
|
95
NQ/chase.c
Normal file
95
NQ/chase.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// chase.c -- chase camera code
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "world.h" /* trace_t */
|
||||
|
||||
cvar_t chase_back = { "chase_back", "100" };
|
||||
cvar_t chase_up = { "chase_up", "16" };
|
||||
cvar_t chase_right = { "chase_right", "0" };
|
||||
cvar_t chase_active = { "chase_active", "0" };
|
||||
|
||||
vec3_t chase_pos;
|
||||
vec3_t chase_angles;
|
||||
|
||||
vec3_t chase_dest;
|
||||
vec3_t chase_dest_angles;
|
||||
|
||||
|
||||
void
|
||||
Chase_Init(void)
|
||||
{
|
||||
Cvar_RegisterVariable(&chase_back);
|
||||
Cvar_RegisterVariable(&chase_up);
|
||||
Cvar_RegisterVariable(&chase_right);
|
||||
Cvar_RegisterVariable(&chase_active);
|
||||
}
|
||||
|
||||
void
|
||||
Chase_Reset(void)
|
||||
{
|
||||
// for respawning and teleporting
|
||||
// start position 12 units behind head
|
||||
}
|
||||
|
||||
void
|
||||
TraceLine(vec3_t start, vec3_t end, vec3_t impact)
|
||||
{
|
||||
trace_t trace;
|
||||
|
||||
memset(&trace, 0, sizeof(trace));
|
||||
SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);
|
||||
|
||||
VectorCopy(trace.endpos, impact);
|
||||
}
|
||||
|
||||
void
|
||||
Chase_Update(void)
|
||||
{
|
||||
int i;
|
||||
float dist;
|
||||
vec3_t forward, up, right;
|
||||
vec3_t dest, stop;
|
||||
|
||||
|
||||
// if can't see player, reset
|
||||
AngleVectors(cl.viewangles, forward, right, up);
|
||||
|
||||
// calc exact destination
|
||||
for (i = 0; i < 3; i++)
|
||||
chase_dest[i] = r_refdef.vieworg[i]
|
||||
- forward[i] * chase_back.value - right[i] * chase_right.value;
|
||||
chase_dest[2] = r_refdef.vieworg[2] + chase_up.value;
|
||||
|
||||
// find the spot the player is looking at
|
||||
VectorMA(r_refdef.vieworg, 4096, forward, dest);
|
||||
TraceLine(r_refdef.vieworg, dest, stop);
|
||||
|
||||
// calculate pitch to look at the same spot from camera
|
||||
VectorSubtract(stop, r_refdef.vieworg, stop);
|
||||
dist = DotProduct(stop, forward);
|
||||
if (dist < 1)
|
||||
dist = 1;
|
||||
r_refdef.viewangles[PITCH] = -atan(stop[2] / dist) / M_PI * 180;
|
||||
|
||||
// move towards destination
|
||||
VectorCopy(chase_dest, r_refdef.vieworg);
|
||||
}
|
365
NQ/cl_demo.c
Normal file
365
NQ/cl_demo.c
Normal file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "cmd.h"
|
||||
#include "console.h"
|
||||
#include "host.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
#include "quakedef.h"
|
||||
#include "sys.h"
|
||||
|
||||
static void CL_FinishTimeDemo(void);
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
DEMO CODE
|
||||
|
||||
When a demo is playing back, all NET_SendMessages are skipped, and
|
||||
NET_GetMessages are read from the demo file.
|
||||
|
||||
Whenever cl.time gets past the last received message, another message is
|
||||
read from the demo file.
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_StopPlayback
|
||||
|
||||
Called when a demo file runs out, or the user starts a game
|
||||
==============
|
||||
*/
|
||||
void
|
||||
CL_StopPlayback(void)
|
||||
{
|
||||
if (!cls.demoplayback)
|
||||
return;
|
||||
|
||||
fclose(cls.demofile);
|
||||
cls.demoplayback = false;
|
||||
cls.demofile = NULL;
|
||||
cls.state = ca_disconnected;
|
||||
|
||||
if (cls.timedemo)
|
||||
CL_FinishTimeDemo();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_WriteDemoMessage
|
||||
|
||||
Dumps the current net message, prefixed by the length and view angles
|
||||
====================
|
||||
*/
|
||||
static void
|
||||
CL_WriteDemoMessage(void)
|
||||
{
|
||||
int len;
|
||||
int i;
|
||||
float f;
|
||||
|
||||
len = LittleLong(net_message.cursize);
|
||||
fwrite(&len, 4, 1, cls.demofile);
|
||||
for (i = 0; i < 3; i++) {
|
||||
f = LittleFloat(cl.viewangles[i]);
|
||||
fwrite(&f, 4, 1, cls.demofile);
|
||||
}
|
||||
fwrite(net_message.data, net_message.cursize, 1, cls.demofile);
|
||||
fflush(cls.demofile);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_GetMessage
|
||||
|
||||
Handles recording and playback of demos, on top of NET_ code
|
||||
====================
|
||||
*/
|
||||
int
|
||||
CL_GetMessage(void)
|
||||
{
|
||||
int r, i;
|
||||
float f;
|
||||
|
||||
if (cls.demoplayback) {
|
||||
// decide if it is time to grab the next message
|
||||
// allways grab until fully connected
|
||||
if (cls.state == ca_active) {
|
||||
if (cls.timedemo) {
|
||||
if (host_framecount == cls.td_lastframe)
|
||||
return 0; // allready read this frame's message
|
||||
|
||||
cls.td_lastframe = host_framecount;
|
||||
|
||||
// if this is the second frame, grab the real td_starttime
|
||||
// so the bogus time on the first frame doesn't count
|
||||
if (host_framecount == cls.td_startframe + 1)
|
||||
cls.td_starttime = realtime;
|
||||
} else if (cl.time <= cl.mtime[0]) {
|
||||
// don't need another message yet
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// get the next message
|
||||
fread(&net_message.cursize, 4, 1, cls.demofile);
|
||||
VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
|
||||
for (i = 0; i < 3; i++) {
|
||||
r = fread(&f, 4, 1, cls.demofile);
|
||||
cl.mviewangles[0][i] = LittleFloat(f);
|
||||
}
|
||||
|
||||
net_message.cursize = LittleLong(net_message.cursize);
|
||||
if (net_message.cursize > MAX_MSGLEN)
|
||||
Sys_Error("Demo message > MAX_MSGLEN");
|
||||
r = fread(net_message.data, net_message.cursize, 1, cls.demofile);
|
||||
if (r != 1) {
|
||||
CL_StopPlayback();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
r = NET_GetMessage(cls.netcon);
|
||||
|
||||
if (r != 1 && r != 2)
|
||||
return r;
|
||||
|
||||
// discard nop keepalive message
|
||||
if (net_message.cursize == 1 && net_message.data[0] == svc_nop)
|
||||
Con_Printf("<-- server to client keepalive\n");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (cls.demorecording)
|
||||
CL_WriteDemoMessage();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_Stop_f
|
||||
|
||||
stop recording a demo
|
||||
====================
|
||||
*/
|
||||
void
|
||||
CL_Stop_f(void)
|
||||
{
|
||||
if (cmd_source != src_command)
|
||||
return;
|
||||
|
||||
if (!cls.demorecording) {
|
||||
Con_Printf("Not recording a demo.\n");
|
||||
return;
|
||||
}
|
||||
// write a disconnect message to the demo file
|
||||
SZ_Clear(&net_message);
|
||||
MSG_WriteByte(&net_message, svc_disconnect);
|
||||
CL_WriteDemoMessage();
|
||||
|
||||
// finish up
|
||||
fclose(cls.demofile);
|
||||
cls.demofile = NULL;
|
||||
cls.demorecording = false;
|
||||
Con_Printf("Completed demo\n");
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_Record_f
|
||||
|
||||
record <demoname> <map> [cd track]
|
||||
====================
|
||||
*/
|
||||
void
|
||||
CL_Record_f(void)
|
||||
{
|
||||
int c;
|
||||
char name[MAX_OSPATH];
|
||||
int track;
|
||||
|
||||
if (cmd_source != src_command)
|
||||
return;
|
||||
|
||||
c = Cmd_Argc();
|
||||
if (c != 2 && c != 3 && c != 4) {
|
||||
Con_Printf("record <demoname> [<map> [cd track]]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strstr(Cmd_Argv(1), "..")) {
|
||||
Con_Printf("Relative pathnames are not allowed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == 2 && cls.state >= ca_connected) {
|
||||
Con_Printf("Can not record - already connected to server\n"
|
||||
"Client demo recording must be started before"
|
||||
" connecting\n");
|
||||
return;
|
||||
}
|
||||
// write the forced cd track number, or -1
|
||||
if (c == 4) {
|
||||
track = atoi(Cmd_Argv(3));
|
||||
Con_Printf("Forcing CD track to %i\n", cls.forcetrack);
|
||||
} else
|
||||
track = -1;
|
||||
|
||||
sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1));
|
||||
|
||||
//
|
||||
// start the map up
|
||||
//
|
||||
if (c > 2)
|
||||
Cmd_ExecuteString(va("map %s", Cmd_Argv(2)), src_command);
|
||||
|
||||
//
|
||||
// open the demo file
|
||||
//
|
||||
COM_DefaultExtension(name, ".dem");
|
||||
|
||||
Con_Printf("recording to %s.\n", name);
|
||||
cls.demofile = fopen(name, "wb");
|
||||
if (!cls.demofile) {
|
||||
Con_Printf("ERROR: couldn't open.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cls.forcetrack = track;
|
||||
fprintf(cls.demofile, "%i\n", cls.forcetrack);
|
||||
|
||||
cls.demorecording = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_PlayDemo_f
|
||||
|
||||
play [demoname]
|
||||
====================
|
||||
*/
|
||||
void
|
||||
CL_PlayDemo_f(void)
|
||||
{
|
||||
char name[256];
|
||||
int c;
|
||||
qboolean neg = false;
|
||||
|
||||
if (cmd_source != src_command)
|
||||
return;
|
||||
|
||||
if (Cmd_Argc() != 2) {
|
||||
Con_Printf("play <demoname> : plays a demo\n");
|
||||
return;
|
||||
}
|
||||
//
|
||||
// disconnect from server
|
||||
//
|
||||
CL_Disconnect();
|
||||
|
||||
//
|
||||
// open the demo file
|
||||
//
|
||||
strcpy(name, Cmd_Argv(1));
|
||||
COM_DefaultExtension(name, ".dem");
|
||||
|
||||
Con_Printf("Playing demo from %s.\n", name);
|
||||
COM_FOpenFile(name, &cls.demofile);
|
||||
if (!cls.demofile) {
|
||||
Con_Printf("ERROR: couldn't open.\n");
|
||||
cls.demonum = -1; // stop demo loop
|
||||
return;
|
||||
}
|
||||
|
||||
cls.demoplayback = true;
|
||||
cls.state = ca_connected;
|
||||
cls.forcetrack = 0;
|
||||
|
||||
while ((c = getc(cls.demofile)) != '\n')
|
||||
if (c == '-')
|
||||
neg = true;
|
||||
else
|
||||
cls.forcetrack = cls.forcetrack * 10 + (c - '0');
|
||||
|
||||
if (neg)
|
||||
cls.forcetrack = -cls.forcetrack;
|
||||
// ZOID, fscanf is evil
|
||||
// fscanf (cls.demofile, "%i\n", &cls.forcetrack);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_FinishTimeDemo
|
||||
|
||||
====================
|
||||
*/
|
||||
static void
|
||||
CL_FinishTimeDemo(void)
|
||||
{
|
||||
int frames;
|
||||
float time;
|
||||
|
||||
cls.timedemo = false;
|
||||
|
||||
// the first frame didn't count
|
||||
frames = (host_framecount - cls.td_startframe) - 1;
|
||||
time = realtime - cls.td_starttime;
|
||||
if (!time)
|
||||
time = 1;
|
||||
Con_Printf("%i frames %5.1f seconds %5.1f fps\n", frames, time,
|
||||
frames / time);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_TimeDemo_f
|
||||
|
||||
timedemo [demoname]
|
||||
====================
|
||||
*/
|
||||
void
|
||||
CL_TimeDemo_f(void)
|
||||
{
|
||||
if (cmd_source != src_command)
|
||||
return;
|
||||
|
||||
if (Cmd_Argc() != 2) {
|
||||
Con_Printf("timedemo <demoname> : gets demo speeds\n");
|
||||
return;
|
||||
}
|
||||
|
||||
CL_PlayDemo_f();
|
||||
|
||||
// cls.td_starttime will be grabbed at the second frame of the demo, so
|
||||
// all the loading time doesn't get counted
|
||||
|
||||
cls.timedemo = true;
|
||||
cls.td_startframe = host_framecount;
|
||||
cls.td_lastframe = -1; // get a new message this frame
|
||||
}
|
616
NQ/cl_input.c
Normal file
616
NQ/cl_input.c
Normal file
@ -0,0 +1,616 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cl.input.c -- builds an intended movement command to send to the server
|
||||
|
||||
// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
|
||||
// rights reserved.
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "host.h"
|
||||
#include "client.h"
|
||||
#include "cmd.h"
|
||||
#include "console.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
KEY BUTTONS
|
||||
|
||||
Continuous button event tracking is complicated by the fact that two different
|
||||
input sources (say, mouse button 1 and the control key) can both press the
|
||||
same button, but the button should only be released when both of the
|
||||
pressing key have been released.
|
||||
|
||||
When a key event issues a button command (+forward, +attack, etc), it appends
|
||||
its key number as a parameter to the command so it can be matched up with
|
||||
the release.
|
||||
|
||||
state bit 0 is the current state of the key
|
||||
state bit 1 is edge triggered on the up to down transition
|
||||
state bit 2 is edge triggered on the down to up transition
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
kbutton_t in_mlook, in_klook;
|
||||
kbutton_t in_left, in_right, in_forward, in_back;
|
||||
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_up, in_down;
|
||||
|
||||
int in_impulse;
|
||||
|
||||
|
||||
void
|
||||
KeyDown(kbutton_t *b)
|
||||
{
|
||||
int k;
|
||||
char *c;
|
||||
|
||||
c = Cmd_Argv(1);
|
||||
if (c[0])
|
||||
k = atoi(c);
|
||||
else
|
||||
k = -1; // typed manually at the console for continuous down
|
||||
|
||||
if (k == b->down[0] || k == b->down[1])
|
||||
return; // repeating key
|
||||
|
||||
if (!b->down[0])
|
||||
b->down[0] = k;
|
||||
else if (!b->down[1])
|
||||
b->down[1] = k;
|
||||
else {
|
||||
Con_Printf("Three keys down for a button!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (b->state & 1)
|
||||
return; // still down
|
||||
b->state |= 1 + 2; // down + impulse down
|
||||
}
|
||||
|
||||
void
|
||||
KeyUp(kbutton_t *b)
|
||||
{
|
||||
int k;
|
||||
char *c;
|
||||
|
||||
c = Cmd_Argv(1);
|
||||
if (c[0])
|
||||
k = atoi(c);
|
||||
else { // typed manually at the console, assume for unsticking, so clear all
|
||||
b->down[0] = b->down[1] = 0;
|
||||
b->state = 4; // impulse up
|
||||
return;
|
||||
}
|
||||
|
||||
if (b->down[0] == k)
|
||||
b->down[0] = 0;
|
||||
else if (b->down[1] == k)
|
||||
b->down[1] = 0;
|
||||
else
|
||||
return; // key up without coresponding down (menu pass through)
|
||||
if (b->down[0] || b->down[1])
|
||||
return; // some other key is still holding it down
|
||||
|
||||
if (!(b->state & 1))
|
||||
return; // still up (this should not happen)
|
||||
b->state &= ~1; // now up
|
||||
b->state |= 4; // impulse up
|
||||
}
|
||||
|
||||
void
|
||||
IN_KLookDown(void)
|
||||
{
|
||||
KeyDown(&in_klook);
|
||||
}
|
||||
|
||||
void
|
||||
IN_KLookUp(void)
|
||||
{
|
||||
KeyUp(&in_klook);
|
||||
}
|
||||
|
||||
void
|
||||
IN_MLookDown(void)
|
||||
{
|
||||
KeyDown(&in_mlook);
|
||||
}
|
||||
|
||||
void
|
||||
IN_MLookUp(void)
|
||||
{
|
||||
KeyUp(&in_mlook);
|
||||
if (!(in_mlook.state & 1) && lookspring.value)
|
||||
V_StartPitchDrift();
|
||||
}
|
||||
|
||||
void
|
||||
IN_UpDown(void)
|
||||
{
|
||||
KeyDown(&in_up);
|
||||
}
|
||||
|
||||
void
|
||||
IN_UpUp(void)
|
||||
{
|
||||
KeyUp(&in_up);
|
||||
}
|
||||
|
||||
void
|
||||
IN_DownDown(void)
|
||||
{
|
||||
KeyDown(&in_down);
|
||||
}
|
||||
|
||||
void
|
||||
IN_DownUp(void)
|
||||
{
|
||||
KeyUp(&in_down);
|
||||
}
|
||||
|
||||
void
|
||||
IN_LeftDown(void)
|
||||
{
|
||||
KeyDown(&in_left);
|
||||
}
|
||||
|
||||
void
|
||||
IN_LeftUp(void)
|
||||
{
|
||||
KeyUp(&in_left);
|
||||
}
|
||||
|
||||
void
|
||||
IN_RightDown(void)
|
||||
{
|
||||
KeyDown(&in_right);
|
||||
}
|
||||
|
||||
void
|
||||
IN_RightUp(void)
|
||||
{
|
||||
KeyUp(&in_right);
|
||||
}
|
||||
|
||||
void
|
||||
IN_ForwardDown(void)
|
||||
{
|
||||
KeyDown(&in_forward);
|
||||
}
|
||||
|
||||
void
|
||||
IN_ForwardUp(void)
|
||||
{
|
||||
KeyUp(&in_forward);
|
||||
}
|
||||
|
||||
void
|
||||
IN_BackDown(void)
|
||||
{
|
||||
KeyDown(&in_back);
|
||||
}
|
||||
|
||||
void
|
||||
IN_BackUp(void)
|
||||
{
|
||||
KeyUp(&in_back);
|
||||
}
|
||||
|
||||
void
|
||||
IN_LookupDown(void)
|
||||
{
|
||||
KeyDown(&in_lookup);
|
||||
}
|
||||
|
||||
void
|
||||
IN_LookupUp(void)
|
||||
{
|
||||
KeyUp(&in_lookup);
|
||||
}
|
||||
|
||||
void
|
||||
IN_LookdownDown(void)
|
||||
{
|
||||
KeyDown(&in_lookdown);
|
||||
}
|
||||
|
||||
void
|
||||
IN_LookdownUp(void)
|
||||
{
|
||||
KeyUp(&in_lookdown);
|
||||
}
|
||||
|
||||
void
|
||||
IN_MoveleftDown(void)
|
||||
{
|
||||
KeyDown(&in_moveleft);
|
||||
}
|
||||
|
||||
void
|
||||
IN_MoveleftUp(void)
|
||||
{
|
||||
KeyUp(&in_moveleft);
|
||||
}
|
||||
|
||||
void
|
||||
IN_MoverightDown(void)
|
||||
{
|
||||
KeyDown(&in_moveright);
|
||||
}
|
||||
|
||||
void
|
||||
IN_MoverightUp(void)
|
||||
{
|
||||
KeyUp(&in_moveright);
|
||||
}
|
||||
|
||||
void
|
||||
IN_SpeedDown(void)
|
||||
{
|
||||
KeyDown(&in_speed);
|
||||
}
|
||||
|
||||
void
|
||||
IN_SpeedUp(void)
|
||||
{
|
||||
KeyUp(&in_speed);
|
||||
}
|
||||
|
||||
void
|
||||
IN_StrafeDown(void)
|
||||
{
|
||||
KeyDown(&in_strafe);
|
||||
}
|
||||
|
||||
void
|
||||
IN_StrafeUp(void)
|
||||
{
|
||||
KeyUp(&in_strafe);
|
||||
}
|
||||
|
||||
void
|
||||
IN_AttackDown(void)
|
||||
{
|
||||
KeyDown(&in_attack);
|
||||
}
|
||||
|
||||
void
|
||||
IN_AttackUp(void)
|
||||
{
|
||||
KeyUp(&in_attack);
|
||||
}
|
||||
|
||||
void
|
||||
IN_UseDown(void)
|
||||
{
|
||||
KeyDown(&in_use);
|
||||
}
|
||||
|
||||
void
|
||||
IN_UseUp(void)
|
||||
{
|
||||
KeyUp(&in_use);
|
||||
}
|
||||
|
||||
void
|
||||
IN_JumpDown(void)
|
||||
{
|
||||
KeyDown(&in_jump);
|
||||
}
|
||||
|
||||
void
|
||||
IN_JumpUp(void)
|
||||
{
|
||||
KeyUp(&in_jump);
|
||||
}
|
||||
|
||||
void
|
||||
IN_Impulse(void)
|
||||
{
|
||||
in_impulse = Q_atoi(Cmd_Argv(1));
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_KeyState
|
||||
|
||||
Returns 0.25 if a key was pressed and released during the frame,
|
||||
0.5 if it was pressed and held
|
||||
0 if held then released, and
|
||||
1.0 if held for the entire time
|
||||
===============
|
||||
*/
|
||||
float
|
||||
CL_KeyState(kbutton_t *key)
|
||||
{
|
||||
float val;
|
||||
qboolean impulsedown, impulseup, down;
|
||||
|
||||
impulsedown = key->state & 2;
|
||||
impulseup = key->state & 4;
|
||||
down = key->state & 1;
|
||||
val = 0;
|
||||
|
||||
if (impulsedown && !impulseup) {
|
||||
if (down)
|
||||
val = 0.5; // pressed and held this frame
|
||||
else
|
||||
val = 0; // I_Error ();
|
||||
}
|
||||
// FIXME: both alternatives zero?
|
||||
if (impulseup && !impulsedown) {
|
||||
if (down)
|
||||
val = 0; // I_Error ();
|
||||
else
|
||||
val = 0; // released this frame
|
||||
}
|
||||
if (!impulsedown && !impulseup) {
|
||||
if (down)
|
||||
val = 1.0; // held the entire frame
|
||||
else
|
||||
val = 0; // up the entire frame
|
||||
}
|
||||
if (impulsedown && impulseup) {
|
||||
if (down)
|
||||
val = 0.75; // released and re-pressed this frame
|
||||
else
|
||||
val = 0.25; // pressed and released this frame
|
||||
}
|
||||
|
||||
key->state &= 1; // clear impulses
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
|
||||
cvar_t cl_upspeed = { "cl_upspeed", "200" };
|
||||
cvar_t cl_forwardspeed = { "cl_forwardspeed", "200", true };
|
||||
cvar_t cl_backspeed = { "cl_backspeed", "200", true };
|
||||
cvar_t cl_sidespeed = { "cl_sidespeed", "350" };
|
||||
|
||||
cvar_t cl_movespeedkey = { "cl_movespeedkey", "2.0" };
|
||||
|
||||
cvar_t cl_yawspeed = { "cl_yawspeed", "140" };
|
||||
cvar_t cl_pitchspeed = { "cl_pitchspeed", "150" };
|
||||
|
||||
cvar_t cl_anglespeedkey = { "cl_anglespeedkey", "1.5" };
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CL_AdjustAngles
|
||||
|
||||
Moves the local angle positions
|
||||
================
|
||||
*/
|
||||
void
|
||||
CL_AdjustAngles(void)
|
||||
{
|
||||
float speed;
|
||||
float up, down;
|
||||
|
||||
if (in_speed.state & 1)
|
||||
speed = host_frametime * cl_anglespeedkey.value;
|
||||
else
|
||||
speed = host_frametime;
|
||||
|
||||
if (!(in_strafe.state & 1)) {
|
||||
cl.viewangles[YAW] -=
|
||||
speed * cl_yawspeed.value * CL_KeyState(&in_right);
|
||||
cl.viewangles[YAW] +=
|
||||
speed * cl_yawspeed.value * CL_KeyState(&in_left);
|
||||
cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
|
||||
}
|
||||
if (in_klook.state & 1) {
|
||||
V_StopPitchDrift();
|
||||
cl.viewangles[PITCH] -=
|
||||
speed * cl_pitchspeed.value * CL_KeyState(&in_forward);
|
||||
cl.viewangles[PITCH] +=
|
||||
speed * cl_pitchspeed.value * CL_KeyState(&in_back);
|
||||
}
|
||||
|
||||
up = CL_KeyState(&in_lookup);
|
||||
down = CL_KeyState(&in_lookdown);
|
||||
|
||||
cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * up;
|
||||
cl.viewangles[PITCH] += speed * cl_pitchspeed.value * down;
|
||||
|
||||
if (up || down)
|
||||
V_StopPitchDrift();
|
||||
|
||||
if (cl.viewangles[PITCH] > 80)
|
||||
cl.viewangles[PITCH] = 80;
|
||||
if (cl.viewangles[PITCH] < -70)
|
||||
cl.viewangles[PITCH] = -70;
|
||||
|
||||
if (cl.viewangles[ROLL] > 50)
|
||||
cl.viewangles[ROLL] = 50;
|
||||
if (cl.viewangles[ROLL] < -50)
|
||||
cl.viewangles[ROLL] = -50;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CL_BaseMove
|
||||
|
||||
Send the intended movement message to the server
|
||||
================
|
||||
*/
|
||||
void
|
||||
CL_BaseMove(usercmd_t *cmd)
|
||||
{
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
CL_AdjustAngles();
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
|
||||
if (in_strafe.state & 1) {
|
||||
cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_right);
|
||||
cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_left);
|
||||
}
|
||||
|
||||
cmd->sidemove += cl_sidespeed.value * CL_KeyState(&in_moveright);
|
||||
cmd->sidemove -= cl_sidespeed.value * CL_KeyState(&in_moveleft);
|
||||
|
||||
cmd->upmove += cl_upspeed.value * CL_KeyState(&in_up);
|
||||
cmd->upmove -= cl_upspeed.value * CL_KeyState(&in_down);
|
||||
|
||||
if (!(in_klook.state & 1)) {
|
||||
cmd->forwardmove += cl_forwardspeed.value * CL_KeyState(&in_forward);
|
||||
cmd->forwardmove -= cl_backspeed.value * CL_KeyState(&in_back);
|
||||
}
|
||||
//
|
||||
// adjust for speed key
|
||||
//
|
||||
if (in_speed.state & 1) {
|
||||
cmd->forwardmove *= cl_movespeedkey.value;
|
||||
cmd->sidemove *= cl_movespeedkey.value;
|
||||
cmd->upmove *= cl_movespeedkey.value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_SendMove
|
||||
==============
|
||||
*/
|
||||
void
|
||||
CL_SendMove(usercmd_t *cmd)
|
||||
{
|
||||
int i;
|
||||
int bits;
|
||||
sizebuf_t buf;
|
||||
byte data[128];
|
||||
|
||||
buf.maxsize = 128;
|
||||
buf.cursize = 0;
|
||||
buf.data = data;
|
||||
|
||||
cl.cmd = *cmd;
|
||||
|
||||
/*
|
||||
* send the movement message
|
||||
*/
|
||||
MSG_WriteByte(&buf, clc_move);
|
||||
MSG_WriteFloat(&buf, cl.mtime[0]); /* so server can get ping times */
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
MSG_WriteAngle(&buf, cl.viewangles[i]);
|
||||
|
||||
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;
|
||||
|
||||
MSG_WriteByte(&buf, bits);
|
||||
MSG_WriteByte(&buf, in_impulse);
|
||||
in_impulse = 0;
|
||||
|
||||
if (cls.demoplayback)
|
||||
return;
|
||||
|
||||
/*
|
||||
* deliver the message
|
||||
*/
|
||||
|
||||
/*
|
||||
* allways dump the first two message, because it may contain leftover
|
||||
* inputs from the last level
|
||||
*/
|
||||
if (++cl.movemessages <= 2)
|
||||
return;
|
||||
|
||||
if (NET_SendUnreliableMessage(cls.netcon, &buf) == -1) {
|
||||
Con_Printf("CL_SendMove: lost server connection\n");
|
||||
CL_Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
CL_InitInput
|
||||
============
|
||||
*/
|
||||
void
|
||||
CL_InitInput(void)
|
||||
{
|
||||
Cmd_AddCommand("+moveup", IN_UpDown);
|
||||
Cmd_AddCommand("-moveup", IN_UpUp);
|
||||
Cmd_AddCommand("+movedown", IN_DownDown);
|
||||
Cmd_AddCommand("-movedown", IN_DownUp);
|
||||
Cmd_AddCommand("+left", IN_LeftDown);
|
||||
Cmd_AddCommand("-left", IN_LeftUp);
|
||||
Cmd_AddCommand("+right", IN_RightDown);
|
||||
Cmd_AddCommand("-right", IN_RightUp);
|
||||
Cmd_AddCommand("+forward", IN_ForwardDown);
|
||||
Cmd_AddCommand("-forward", IN_ForwardUp);
|
||||
Cmd_AddCommand("+back", IN_BackDown);
|
||||
Cmd_AddCommand("-back", IN_BackUp);
|
||||
Cmd_AddCommand("+lookup", IN_LookupDown);
|
||||
Cmd_AddCommand("-lookup", IN_LookupUp);
|
||||
Cmd_AddCommand("+lookdown", IN_LookdownDown);
|
||||
Cmd_AddCommand("-lookdown", IN_LookdownUp);
|
||||
Cmd_AddCommand("+strafe", IN_StrafeDown);
|
||||
Cmd_AddCommand("-strafe", IN_StrafeUp);
|
||||
Cmd_AddCommand("+moveleft", IN_MoveleftDown);
|
||||
Cmd_AddCommand("-moveleft", IN_MoveleftUp);
|
||||
Cmd_AddCommand("+moveright", IN_MoverightDown);
|
||||
Cmd_AddCommand("-moveright", IN_MoverightUp);
|
||||
Cmd_AddCommand("+speed", IN_SpeedDown);
|
||||
Cmd_AddCommand("-speed", IN_SpeedUp);
|
||||
Cmd_AddCommand("+attack", IN_AttackDown);
|
||||
Cmd_AddCommand("-attack", IN_AttackUp);
|
||||
Cmd_AddCommand("+use", IN_UseDown);
|
||||
Cmd_AddCommand("-use", IN_UseUp);
|
||||
Cmd_AddCommand("+jump", IN_JumpDown);
|
||||
Cmd_AddCommand("-jump", IN_JumpUp);
|
||||
Cmd_AddCommand("impulse", IN_Impulse);
|
||||
Cmd_AddCommand("+klook", IN_KLookDown);
|
||||
Cmd_AddCommand("-klook", IN_KLookUp);
|
||||
Cmd_AddCommand("+mlook", IN_MLookDown);
|
||||
Cmd_AddCommand("-mlook", IN_MLookUp);
|
||||
|
||||
}
|
727
NQ/cl_main.c
Normal file
727
NQ/cl_main.c
Normal file
@ -0,0 +1,727 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cl_main.c -- client main loop
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "host.h"
|
||||
#include "cvar.h"
|
||||
#include "client.h"
|
||||
#include "server.h"
|
||||
#include "sound.h"
|
||||
#include "console.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
#include "screen.h"
|
||||
#include "cmd.h"
|
||||
#include "render.h"
|
||||
#include "input.h"
|
||||
|
||||
#ifdef GLQUAKE
|
||||
# include "gl_model.h"
|
||||
#else
|
||||
# include "model.h"
|
||||
#endif
|
||||
|
||||
// we need to declare some mouse variables here, because the menu system
|
||||
// references them even when on a unix system.
|
||||
|
||||
// these two are not intended to be set directly
|
||||
cvar_t cl_name = { "_cl_name", "player", true };
|
||||
cvar_t cl_color = { "_cl_color", "0", true };
|
||||
|
||||
cvar_t cl_shownet = { "cl_shownet", "0" }; // can be 0, 1, or 2
|
||||
cvar_t cl_nolerp = { "cl_nolerp", "0" };
|
||||
|
||||
cvar_t lookspring = { "lookspring", "0", true };
|
||||
cvar_t lookstrafe = { "lookstrafe", "0", true };
|
||||
cvar_t sensitivity = { "sensitivity", "3", true };
|
||||
|
||||
cvar_t m_pitch = { "m_pitch", "0.022", true };
|
||||
cvar_t m_yaw = { "m_yaw", "0.022", true };
|
||||
cvar_t m_forward = { "m_forward", "1", true };
|
||||
cvar_t m_side = { "m_side", "0.8", true };
|
||||
|
||||
|
||||
client_static_t cls;
|
||||
client_state_t cl;
|
||||
|
||||
// FIXME: put these on hunk?
|
||||
efrag_t cl_efrags[MAX_EFRAGS];
|
||||
entity_t cl_entities[MAX_EDICTS];
|
||||
entity_t cl_static_entities[MAX_STATIC_ENTITIES];
|
||||
lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
|
||||
dlight_t cl_dlights[MAX_DLIGHTS];
|
||||
|
||||
int cl_numvisedicts;
|
||||
entity_t *cl_visedicts[MAX_VISEDICTS];
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_ClearState
|
||||
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
CL_ClearState(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!sv.active)
|
||||
Host_ClearMemory();
|
||||
|
||||
// wipe the entire cl structure
|
||||
memset(&cl, 0, sizeof(cl));
|
||||
|
||||
SZ_Clear(&cls.message);
|
||||
|
||||
// clear other arrays
|
||||
memset(cl_efrags, 0, sizeof(cl_efrags));
|
||||
memset(cl_entities, 0, sizeof(cl_entities));
|
||||
memset(cl_dlights, 0, sizeof(cl_dlights));
|
||||
memset(cl_lightstyle, 0, sizeof(cl_lightstyle));
|
||||
memset(cl_temp_entities, 0, sizeof(cl_temp_entities));
|
||||
memset(cl_beams, 0, sizeof(cl_beams));
|
||||
|
||||
//
|
||||
// allocate the efrags and chain together into a free list
|
||||
//
|
||||
cl.free_efrags = cl_efrags;
|
||||
for (i = 0; i < MAX_EFRAGS - 1; i++)
|
||||
cl.free_efrags[i].entnext = &cl.free_efrags[i + 1];
|
||||
cl.free_efrags[i].entnext = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_Disconnect
|
||||
|
||||
Sends a disconnect message to the server
|
||||
This is also called on Host_Error, so it shouldn't cause any errors
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
CL_Disconnect(void)
|
||||
{
|
||||
// stop sounds (especially looping!)
|
||||
S_StopAllSounds(true);
|
||||
|
||||
// bring the console down and fade the colors back to normal
|
||||
// SCR_BringDownConsole ();
|
||||
|
||||
// if running a local server, shut it down
|
||||
if (cls.demoplayback)
|
||||
CL_StopPlayback();
|
||||
else if (cls.state >= ca_connected) {
|
||||
if (cls.demorecording)
|
||||
CL_Stop_f();
|
||||
|
||||
Con_DPrintf("Sending clc_disconnect\n");
|
||||
SZ_Clear(&cls.message);
|
||||
MSG_WriteByte(&cls.message, clc_disconnect);
|
||||
NET_SendUnreliableMessage(cls.netcon, &cls.message);
|
||||
SZ_Clear(&cls.message);
|
||||
NET_Close(cls.netcon);
|
||||
|
||||
cls.state = ca_disconnected;
|
||||
if (sv.active)
|
||||
Host_ShutdownServer(false);
|
||||
}
|
||||
|
||||
cls.demoplayback = false;
|
||||
cls.timedemo = false;
|
||||
cls.signon = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CL_Disconnect_f(void)
|
||||
{
|
||||
CL_Disconnect();
|
||||
if (sv.active)
|
||||
Host_ShutdownServer(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_EstablishConnection
|
||||
|
||||
Host should be either "local" or a net address to be passed on
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
CL_EstablishConnection(char *host)
|
||||
{
|
||||
if (cls.state == ca_dedicated)
|
||||
return;
|
||||
if (cls.demoplayback)
|
||||
return;
|
||||
|
||||
CL_Disconnect();
|
||||
|
||||
cls.netcon = NET_Connect(host);
|
||||
if (!cls.netcon)
|
||||
Host_Error("CL_Connect: connect failed");
|
||||
|
||||
Con_DPrintf("CL_EstablishConnection: connected to %s\n", host);
|
||||
|
||||
cls.demonum = -1; // not in the demo loop now
|
||||
cls.state = ca_connected;
|
||||
cls.signon = 0; // need all the signon messages before playing
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_SignonReply
|
||||
|
||||
An svc_signonnum has been received, perform a client side setup
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
CL_SignonReply(void)
|
||||
{
|
||||
char str[8192];
|
||||
|
||||
Con_DPrintf("CL_SignonReply: %i\n", cls.signon);
|
||||
|
||||
switch (cls.signon) {
|
||||
case 1:
|
||||
MSG_WriteByte(&cls.message, clc_stringcmd);
|
||||
MSG_WriteString(&cls.message, "prespawn");
|
||||
break;
|
||||
|
||||
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_WriteString(&cls.message, va("color %i %i\n",
|
||||
((int)cl_color.value) >> 4,
|
||||
((int)cl_color.value) & 15));
|
||||
|
||||
MSG_WriteByte(&cls.message, clc_stringcmd);
|
||||
sprintf(str, "spawn %s", cls.spawnparms);
|
||||
MSG_WriteString(&cls.message, str);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
MSG_WriteByte(&cls.message, clc_stringcmd);
|
||||
MSG_WriteString(&cls.message, "begin");
|
||||
Cache_Report(); // print remaining memory
|
||||
|
||||
// FIXME - this the right place for it?
|
||||
cls.state = ca_firstupdate;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
SCR_EndLoadingPlaque(); // allow normal screen updates
|
||||
|
||||
// FIXME - this the right place for it?
|
||||
cls.state = ca_active;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_NextDemo
|
||||
|
||||
Called to play the next demo in the demo loop
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
CL_NextDemo(void)
|
||||
{
|
||||
char str[1024];
|
||||
|
||||
if (cls.demonum == -1)
|
||||
return; // don't play demos
|
||||
|
||||
SCR_BeginLoadingPlaque();
|
||||
|
||||
if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS) {
|
||||
cls.demonum = 0;
|
||||
if (!cls.demos[cls.demonum][0]) {
|
||||
Con_Printf("No demos listed with startdemos\n");
|
||||
cls.demonum = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(str, "playdemo %s\n", cls.demos[cls.demonum]);
|
||||
Cbuf_InsertText(str);
|
||||
cls.demonum++;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_PrintEntities_f
|
||||
==============
|
||||
*/
|
||||
void
|
||||
CL_PrintEntities_f(void)
|
||||
{
|
||||
entity_t *ent;
|
||||
int i;
|
||||
|
||||
for (i = 0, ent = cl_entities; i < cl.num_entities; i++, ent++) {
|
||||
Con_Printf("%3i:", i);
|
||||
if (!ent->model) {
|
||||
Con_Printf("EMPTY\n");
|
||||
continue;
|
||||
}
|
||||
Con_Printf("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n",
|
||||
ent->model->name, ent->frame, ent->origin[0],
|
||||
ent->origin[1], ent->origin[2], ent->angles[0],
|
||||
ent->angles[1], ent->angles[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
SetPal
|
||||
|
||||
Debugging tool, just flashes the screen
|
||||
===============
|
||||
*/
|
||||
void
|
||||
SetPal(int i)
|
||||
{
|
||||
#if 0
|
||||
static int old;
|
||||
byte pal[768];
|
||||
int c;
|
||||
|
||||
if (i == old)
|
||||
return;
|
||||
old = i;
|
||||
|
||||
if (i == 0)
|
||||
VID_SetPalette(host_basepal);
|
||||
else if (i == 1) {
|
||||
for (c = 0; c < 768; c += 3) {
|
||||
pal[c] = 0;
|
||||
pal[c + 1] = 255;
|
||||
pal[c + 2] = 0;
|
||||
}
|
||||
VID_SetPalette(pal);
|
||||
} else {
|
||||
for (c = 0; c < 768; c += 3) {
|
||||
pal[c] = 0;
|
||||
pal[c + 1] = 0;
|
||||
pal[c + 2] = 255;
|
||||
}
|
||||
VID_SetPalette(pal);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_AllocDlight
|
||||
|
||||
===============
|
||||
*/
|
||||
dlight_t *
|
||||
CL_AllocDlight(int key)
|
||||
{
|
||||
int i;
|
||||
dlight_t *dl;
|
||||
|
||||
// first look for an exact key match
|
||||
if (key) {
|
||||
dl = cl_dlights;
|
||||
for (i = 0; i < MAX_DLIGHTS; i++, dl++) {
|
||||
if (dl->key == key) {
|
||||
memset(dl, 0, sizeof(*dl));
|
||||
dl->key = key;
|
||||
return dl;
|
||||
}
|
||||
}
|
||||
}
|
||||
// then look for anything else
|
||||
dl = cl_dlights;
|
||||
for (i = 0; i < MAX_DLIGHTS; i++, dl++) {
|
||||
if (dl->die < cl.time) {
|
||||
memset(dl, 0, sizeof(*dl));
|
||||
dl->key = key;
|
||||
return dl;
|
||||
}
|
||||
}
|
||||
|
||||
dl = &cl_dlights[0];
|
||||
memset(dl, 0, sizeof(*dl));
|
||||
dl->key = key;
|
||||
return dl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_DecayLights
|
||||
|
||||
===============
|
||||
*/
|
||||
void
|
||||
CL_DecayLights(void)
|
||||
{
|
||||
int i;
|
||||
dlight_t *dl;
|
||||
float time;
|
||||
|
||||
time = cl.time - cl.oldtime;
|
||||
|
||||
dl = cl_dlights;
|
||||
for (i = 0; i < MAX_DLIGHTS; i++, dl++) {
|
||||
if (dl->die < cl.time || !dl->radius)
|
||||
continue;
|
||||
|
||||
dl->radius -= time * dl->decay;
|
||||
if (dl->radius < 0)
|
||||
dl->radius = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_LerpPoint
|
||||
|
||||
Determines the fraction between the last two messages that the objects
|
||||
should be put at.
|
||||
===============
|
||||
*/
|
||||
float
|
||||
CL_LerpPoint(void)
|
||||
{
|
||||
float f, frac;
|
||||
|
||||
f = cl.mtime[0] - cl.mtime[1];
|
||||
|
||||
if (!f || cl_nolerp.value || cls.timedemo || sv.active) {
|
||||
cl.time = cl.mtime[0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (f > 0.1) { // dropped packet, or start of demo
|
||||
cl.mtime[1] = cl.mtime[0] - 0.1;
|
||||
f = 0.1;
|
||||
}
|
||||
frac = (cl.time - cl.mtime[1]) / f;
|
||||
//Con_Printf ("frac: %f\n",frac);
|
||||
if (frac < 0) {
|
||||
if (frac < -0.01) {
|
||||
SetPal(1);
|
||||
cl.time = cl.mtime[1];
|
||||
// Con_Printf ("low frac\n");
|
||||
}
|
||||
frac = 0;
|
||||
} else if (frac > 1) {
|
||||
if (frac > 1.01) {
|
||||
SetPal(2);
|
||||
cl.time = cl.mtime[0];
|
||||
// Con_Printf ("high frac\n");
|
||||
}
|
||||
frac = 1;
|
||||
} else
|
||||
SetPal(0);
|
||||
|
||||
return frac;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_RelinkEntities
|
||||
===============
|
||||
*/
|
||||
void
|
||||
CL_RelinkEntities(void)
|
||||
{
|
||||
entity_t *ent;
|
||||
int i, j;
|
||||
float frac, f, d;
|
||||
vec3_t delta;
|
||||
float bobjrotate;
|
||||
vec3_t oldorg;
|
||||
dlight_t *dl;
|
||||
|
||||
// determine partial update time
|
||||
frac = CL_LerpPoint();
|
||||
|
||||
cl_numvisedicts = 0;
|
||||
|
||||
//
|
||||
// interpolate player info
|
||||
//
|
||||
for (i = 0; i < 3; i++)
|
||||
cl.velocity[i] = cl.mvelocity[1][i] +
|
||||
frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);
|
||||
|
||||
if (cls.demoplayback) {
|
||||
// interpolate the angles
|
||||
for (j = 0; j < 3; j++) {
|
||||
d = cl.mviewangles[0][j] - cl.mviewangles[1][j];
|
||||
if (d > 180)
|
||||
d -= 360;
|
||||
else if (d < -180)
|
||||
d += 360;
|
||||
cl.viewangles[j] = cl.mviewangles[1][j] + frac * d;
|
||||
}
|
||||
}
|
||||
|
||||
bobjrotate = anglemod(100 * cl.time);
|
||||
|
||||
// start on the entity after the world
|
||||
for (i = 1, ent = cl_entities + 1; i < cl.num_entities; i++, ent++) {
|
||||
if (!ent->model) { // empty slot
|
||||
if (ent->forcelink)
|
||||
R_RemoveEfrags(ent); // just became empty
|
||||
continue;
|
||||
}
|
||||
// if the object wasn't included in the last packet, remove it
|
||||
if (ent->msgtime != cl.mtime[0]) {
|
||||
ent->model = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
VectorCopy(ent->origin, oldorg);
|
||||
|
||||
if (ent->forcelink) { // the entity was not updated in the last message
|
||||
// so move to the final spot
|
||||
VectorCopy(ent->msg_origins[0], ent->origin);
|
||||
VectorCopy(ent->msg_angles[0], ent->angles);
|
||||
} 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
|
||||
}
|
||||
|
||||
// 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
|
||||
if (ent->model->flags & EF_ROTATE)
|
||||
ent->angles[1] = bobjrotate;
|
||||
|
||||
if (ent->effects & EF_BRIGHTFIELD)
|
||||
R_EntityParticles(ent);
|
||||
if (ent->effects & EF_MUZZLEFLASH) {
|
||||
vec3_t fv, rv, uv;
|
||||
|
||||
dl = CL_AllocDlight(i);
|
||||
VectorCopy(ent->origin, dl->origin);
|
||||
dl->origin[2] += 16;
|
||||
AngleVectors(ent->angles, fv, rv, uv);
|
||||
|
||||
VectorMA(dl->origin, 18, fv, dl->origin);
|
||||
dl->radius = 200 + (rand() & 31);
|
||||
dl->minlight = 32;
|
||||
dl->die = cl.time + 0.1;
|
||||
}
|
||||
if (ent->effects & EF_BRIGHTLIGHT) {
|
||||
dl = CL_AllocDlight(i);
|
||||
VectorCopy(ent->origin, dl->origin);
|
||||
dl->origin[2] += 16;
|
||||
dl->radius = 400 + (rand() & 31);
|
||||
dl->die = cl.time + 0.001;
|
||||
}
|
||||
if (ent->effects & EF_DIMLIGHT) {
|
||||
dl = CL_AllocDlight(i);
|
||||
VectorCopy(ent->origin, dl->origin);
|
||||
dl->radius = 200 + (rand() & 31);
|
||||
dl->die = cl.time + 0.001;
|
||||
}
|
||||
|
||||
if (ent->model->flags & EF_GIB)
|
||||
R_RocketTrail(oldorg, ent->origin, 2);
|
||||
else if (ent->model->flags & EF_ZOMGIB)
|
||||
R_RocketTrail(oldorg, ent->origin, 4);
|
||||
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);
|
||||
dl = CL_AllocDlight(i);
|
||||
VectorCopy(ent->origin, dl->origin);
|
||||
dl->radius = 200;
|
||||
dl->die = cl.time + 0.01;
|
||||
} else if (ent->model->flags & EF_GRENADE)
|
||||
R_RocketTrail(oldorg, ent->origin, 1);
|
||||
else if (ent->model->flags & EF_TRACER3)
|
||||
R_RocketTrail(oldorg, ent->origin, 6);
|
||||
|
||||
ent->forcelink = false;
|
||||
|
||||
if (i == cl.viewentity && !chase_active.value)
|
||||
continue;
|
||||
|
||||
if (cl_numvisedicts < MAX_VISEDICTS) {
|
||||
cl_visedicts[cl_numvisedicts] = ent;
|
||||
cl_numvisedicts++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_ReadFromServer
|
||||
|
||||
Read all incoming data from the server
|
||||
===============
|
||||
*/
|
||||
int
|
||||
CL_ReadFromServer(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cl.oldtime = cl.time;
|
||||
cl.time += host_frametime;
|
||||
|
||||
do {
|
||||
ret = CL_GetMessage();
|
||||
if (ret == -1)
|
||||
Host_Error("CL_ReadFromServer: lost server connection");
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
cl.last_received_message = realtime;
|
||||
CL_ParseServerMessage();
|
||||
} while (ret && cls.state >= ca_connected);
|
||||
|
||||
if (cl_shownet.value)
|
||||
Con_Printf("\n");
|
||||
|
||||
CL_RelinkEntities();
|
||||
CL_UpdateTEnts();
|
||||
|
||||
//
|
||||
// bring the links up to date
|
||||
//
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_SendCmd
|
||||
=================
|
||||
*/
|
||||
void
|
||||
CL_SendCmd(void)
|
||||
{
|
||||
usercmd_t cmd;
|
||||
|
||||
if (cls.state < ca_connected)
|
||||
return;
|
||||
|
||||
if (cls.state == ca_active) {
|
||||
// get basic movement from keyboard
|
||||
CL_BaseMove(&cmd);
|
||||
|
||||
// allow mice or other external controllers to add to the move
|
||||
IN_Move(&cmd);
|
||||
|
||||
// send the unreliable message
|
||||
CL_SendMove(&cmd);
|
||||
}
|
||||
|
||||
if (cls.demoplayback) {
|
||||
SZ_Clear(&cls.message);
|
||||
return;
|
||||
}
|
||||
// send the reliable message
|
||||
if (!cls.message.cursize)
|
||||
return; // no message at all
|
||||
|
||||
if (!NET_CanSendMessage(cls.netcon)) {
|
||||
Con_DPrintf("CL_WriteToServer: can't send\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NET_SendMessage(cls.netcon, &cls.message) == -1)
|
||||
Host_Error("CL_WriteToServer: lost server connection");
|
||||
|
||||
SZ_Clear(&cls.message);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_Init
|
||||
=================
|
||||
*/
|
||||
void
|
||||
CL_Init(void)
|
||||
{
|
||||
SZ_Alloc(&cls.message, 1024);
|
||||
|
||||
CL_InitInput();
|
||||
CL_InitTEnts();
|
||||
|
||||
//
|
||||
// register our commands
|
||||
//
|
||||
Cvar_RegisterVariable(&cl_name);
|
||||
Cvar_RegisterVariable(&cl_color);
|
||||
Cvar_RegisterVariable(&cl_upspeed);
|
||||
Cvar_RegisterVariable(&cl_forwardspeed);
|
||||
Cvar_RegisterVariable(&cl_backspeed);
|
||||
Cvar_RegisterVariable(&cl_sidespeed);
|
||||
Cvar_RegisterVariable(&cl_movespeedkey);
|
||||
Cvar_RegisterVariable(&cl_yawspeed);
|
||||
Cvar_RegisterVariable(&cl_pitchspeed);
|
||||
Cvar_RegisterVariable(&cl_anglespeedkey);
|
||||
Cvar_RegisterVariable(&cl_shownet);
|
||||
Cvar_RegisterVariable(&cl_nolerp);
|
||||
Cvar_RegisterVariable(&lookspring);
|
||||
Cvar_RegisterVariable(&lookstrafe);
|
||||
Cvar_RegisterVariable(&sensitivity);
|
||||
|
||||
Cvar_RegisterVariable(&m_pitch);
|
||||
Cvar_RegisterVariable(&m_yaw);
|
||||
Cvar_RegisterVariable(&m_forward);
|
||||
Cvar_RegisterVariable(&m_side);
|
||||
|
||||
// Cvar_RegisterVariable (&cl_autofire);
|
||||
|
||||
Cmd_AddCommand("entities", CL_PrintEntities_f);
|
||||
Cmd_AddCommand("disconnect", CL_Disconnect_f);
|
||||
Cmd_AddCommand("record", CL_Record_f);
|
||||
Cmd_AddCommand("stop", CL_Stop_f);
|
||||
Cmd_AddCommand("playdemo", CL_PlayDemo_f);
|
||||
Cmd_AddCommand("timedemo", CL_TimeDemo_f);
|
||||
}
|
967
NQ/cl_parse.c
Normal file
967
NQ/cl_parse.c
Normal file
@ -0,0 +1,967 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cl_parse.c -- parse a message received from the server
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "host.h"
|
||||
#include "client.h"
|
||||
#include "protocol.h"
|
||||
#include "sound.h"
|
||||
#include "server.h"
|
||||
#include "net.h"
|
||||
#include "sys.h"
|
||||
#include "console.h"
|
||||
#include "sbar.h"
|
||||
#include "screen.h"
|
||||
#include "cdaudio.h"
|
||||
#include "cmd.h"
|
||||
|
||||
#ifdef GLQUAKE
|
||||
# include "glquake.h"
|
||||
# include "gl_model.h"
|
||||
#else
|
||||
# include "model.h"
|
||||
#endif
|
||||
|
||||
char *svc_strings[] = {
|
||||
"svc_bad",
|
||||
"svc_nop",
|
||||
"svc_disconnect",
|
||||
"svc_updatestat",
|
||||
"svc_version", // [long] server version
|
||||
"svc_setview", // [short] entity number
|
||||
"svc_sound", // <see code>
|
||||
"svc_time", // [float] server time
|
||||
"svc_print", // [string] null terminated string
|
||||
"svc_stufftext", // [string] stuffed into client's console buffer
|
||||
// the string should be \n terminated
|
||||
"svc_setangle", // [vec3] set the view angle to this absolute value
|
||||
|
||||
"svc_serverinfo", // [long] version
|
||||
// [string] signon string
|
||||
// [string]..[0]model cache [string]...[0]sounds cache
|
||||
// [string]..[0]item cache
|
||||
"svc_lightstyle", // [byte] [string]
|
||||
"svc_updatename", // [byte] [string]
|
||||
"svc_updatefrags", // [byte] [short]
|
||||
"svc_clientdata", // <shortbits + data>
|
||||
"svc_stopsound", // <see code>
|
||||
"svc_updatecolors", // [byte] [byte]
|
||||
"svc_particle", // [vec3] <variable>
|
||||
"svc_damage", // [byte] impact [byte] blood [vec3] from
|
||||
|
||||
"svc_spawnstatic",
|
||||
"OBSOLETE svc_spawnbinary",
|
||||
"svc_spawnbaseline",
|
||||
|
||||
"svc_temp_entity", // <variable>
|
||||
"svc_setpause",
|
||||
"svc_signonnum",
|
||||
"svc_centerprint",
|
||||
"svc_killedmonster",
|
||||
"svc_foundsecret",
|
||||
"svc_spawnstaticsound",
|
||||
"svc_intermission",
|
||||
"svc_finale", // [string] music [string] text
|
||||
"svc_cdtrack", // [byte] track [byte] looptrack
|
||||
"svc_sellscreen",
|
||||
"svc_cutscene"
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
===============
|
||||
CL_EntityNum
|
||||
|
||||
This error checks and tracks the total number of entities
|
||||
===============
|
||||
*/
|
||||
entity_t *
|
||||
CL_EntityNum(int num)
|
||||
{
|
||||
if (num >= cl.num_entities) {
|
||||
if (num >= MAX_EDICTS)
|
||||
Host_Error("CL_EntityNum: %i is an invalid number", num);
|
||||
while (cl.num_entities <= num) {
|
||||
cl_entities[cl.num_entities].colormap = vid.colormap;
|
||||
cl.num_entities++;
|
||||
}
|
||||
}
|
||||
|
||||
return &cl_entities[num];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseStartSoundPacket
|
||||
==================
|
||||
*/
|
||||
void
|
||||
CL_ParseStartSoundPacket(void)
|
||||
{
|
||||
vec3_t pos;
|
||||
int channel, ent;
|
||||
int sound_num;
|
||||
int volume;
|
||||
int field_mask;
|
||||
float attenuation;
|
||||
int i;
|
||||
|
||||
field_mask = MSG_ReadByte();
|
||||
|
||||
if (field_mask & SND_VOLUME)
|
||||
volume = MSG_ReadByte();
|
||||
else
|
||||
volume = DEFAULT_SOUND_PACKET_VOLUME;
|
||||
|
||||
if (field_mask & SND_ATTENUATION)
|
||||
attenuation = MSG_ReadByte() / 64.0;
|
||||
else
|
||||
attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
|
||||
|
||||
channel = MSG_ReadShort();
|
||||
sound_num = MSG_ReadByte();
|
||||
|
||||
ent = channel >> 3;
|
||||
channel &= 7;
|
||||
|
||||
if (ent > MAX_EDICTS)
|
||||
Host_Error("CL_ParseStartSoundPacket: ent = %i", ent);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
pos[i] = MSG_ReadCoord();
|
||||
|
||||
S_StartSound(ent, channel, cl.sound_precache[sound_num], pos,
|
||||
volume / 255.0, attenuation);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_KeepaliveMessage
|
||||
|
||||
When the client is taking a long time to load stuff, send keepalive messages
|
||||
so the server doesn't disconnect.
|
||||
==================
|
||||
*/
|
||||
void
|
||||
CL_KeepaliveMessage(void)
|
||||
{
|
||||
float time;
|
||||
static float lastmsg;
|
||||
int ret;
|
||||
sizebuf_t old;
|
||||
byte olddata[8192];
|
||||
|
||||
if (sv.active)
|
||||
return; // no need if server is local
|
||||
if (cls.demoplayback)
|
||||
return;
|
||||
|
||||
// read messages from server, should just be nops
|
||||
old = net_message;
|
||||
memcpy(olddata, net_message.data, net_message.cursize);
|
||||
|
||||
do {
|
||||
ret = CL_GetMessage();
|
||||
switch (ret) {
|
||||
default:
|
||||
Host_Error("CL_KeepaliveMessage: CL_GetMessage failed");
|
||||
case 0:
|
||||
break; // nothing waiting
|
||||
case 1:
|
||||
Host_Error("CL_KeepaliveMessage: received a message");
|
||||
break;
|
||||
case 2:
|
||||
if (MSG_ReadByte() != svc_nop)
|
||||
Host_Error("CL_KeepaliveMessage: datagram wasn't a nop");
|
||||
break;
|
||||
}
|
||||
} while (ret);
|
||||
|
||||
net_message = old;
|
||||
memcpy(net_message.data, olddata, net_message.cursize);
|
||||
|
||||
// check time
|
||||
time = Sys_DoubleTime();
|
||||
if (time - lastmsg < 5)
|
||||
return;
|
||||
lastmsg = time;
|
||||
|
||||
// write out a nop
|
||||
Con_Printf("--> client to server keepalive\n");
|
||||
|
||||
MSG_WriteByte(&cls.message, clc_nop);
|
||||
NET_SendMessage(cls.netcon, &cls.message);
|
||||
SZ_Clear(&cls.message);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseServerInfo
|
||||
==================
|
||||
*/
|
||||
void
|
||||
CL_ParseServerInfo(void)
|
||||
{
|
||||
char *str;
|
||||
int i;
|
||||
int nummodels, numsounds;
|
||||
char model_precache[MAX_MODELS][MAX_QPATH];
|
||||
char sound_precache[MAX_SOUNDS][MAX_QPATH];
|
||||
|
||||
Con_DPrintf("Serverinfo packet received.\n");
|
||||
//
|
||||
// wipe the client_state_t struct
|
||||
//
|
||||
CL_ClearState();
|
||||
|
||||
// parse protocol version number
|
||||
i = MSG_ReadLong();
|
||||
if (i != PROTOCOL_VERSION) {
|
||||
Con_Printf("Server returned version %i, not %i\n", i,
|
||||
PROTOCOL_VERSION);
|
||||
return;
|
||||
}
|
||||
// parse maxclients
|
||||
cl.maxclients = MSG_ReadByte();
|
||||
if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) {
|
||||
Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
|
||||
return;
|
||||
}
|
||||
cl.scores = Hunk_AllocName(cl.maxclients * sizeof(*cl.scores), "scores");
|
||||
|
||||
// parse gametype
|
||||
cl.gametype = MSG_ReadByte();
|
||||
|
||||
// parse signon message
|
||||
str = MSG_ReadString();
|
||||
strncpy(cl.levelname, str, sizeof(cl.levelname) - 1);
|
||||
|
||||
// seperate the printfs so the server message can have a color
|
||||
Con_Printf
|
||||
("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
|
||||
Con_Printf("%c%s\n", 2, str);
|
||||
|
||||
//
|
||||
// first we go through and touch all of the precache data that still
|
||||
// happens to be in the cache, so precaching something else doesn't
|
||||
// needlessly purge it
|
||||
//
|
||||
|
||||
// precache models
|
||||
memset(cl.model_precache, 0, sizeof(cl.model_precache));
|
||||
for (nummodels = 1;; nummodels++) {
|
||||
str = MSG_ReadString();
|
||||
if (!str[0])
|
||||
break;
|
||||
if (nummodels == MAX_MODELS) {
|
||||
Con_Printf("Server sent too many model precaches\n");
|
||||
return;
|
||||
}
|
||||
strcpy(model_precache[nummodels], str);
|
||||
Mod_TouchModel(str);
|
||||
}
|
||||
|
||||
// precache sounds
|
||||
memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
|
||||
for (numsounds = 1;; numsounds++) {
|
||||
str = MSG_ReadString();
|
||||
if (!str[0])
|
||||
break;
|
||||
if (numsounds == MAX_SOUNDS) {
|
||||
Con_Printf("Server sent too many sound precaches\n");
|
||||
return;
|
||||
}
|
||||
strcpy(sound_precache[numsounds], str);
|
||||
S_TouchSound(str);
|
||||
}
|
||||
|
||||
//
|
||||
// now we try to load everything else until a cache allocation fails
|
||||
//
|
||||
|
||||
for (i = 1; i < nummodels; i++) {
|
||||
cl.model_precache[i] = Mod_ForName(model_precache[i], false);
|
||||
if (cl.model_precache[i] == NULL) {
|
||||
Con_Printf("Model %s not found\n", model_precache[i]);
|
||||
return;
|
||||
}
|
||||
CL_KeepaliveMessage();
|
||||
}
|
||||
|
||||
S_BeginPrecaching();
|
||||
for (i = 1; i < numsounds; i++) {
|
||||
cl.sound_precache[i] = S_PrecacheSound(sound_precache[i]);
|
||||
CL_KeepaliveMessage();
|
||||
}
|
||||
S_EndPrecaching();
|
||||
|
||||
|
||||
// local state
|
||||
cl_entities[0].model = cl.worldmodel = cl.model_precache[1];
|
||||
|
||||
R_NewMap();
|
||||
|
||||
Hunk_Check(); // make sure nothing is hurt
|
||||
|
||||
noclip_anglehack = false; // noclip is turned off at start
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseUpdate
|
||||
|
||||
Parse an entity update message from the server
|
||||
If an entities model or origin changes from frame to frame, it must be
|
||||
relinked. Other attributes can change without relinking.
|
||||
==================
|
||||
*/
|
||||
// FIXME - is this 16 == MAX_CLIENTS?
|
||||
int bitcounts[16];
|
||||
|
||||
void
|
||||
CL_ParseUpdate(int bits)
|
||||
{
|
||||
int i;
|
||||
model_t *model;
|
||||
int modnum;
|
||||
qboolean forcelink;
|
||||
entity_t *ent;
|
||||
int num;
|
||||
|
||||
// FIXME - do this cleanly...
|
||||
#ifdef GLQUAKE
|
||||
int skin;
|
||||
#endif
|
||||
|
||||
if (cls.state == ca_firstupdate) {
|
||||
// first update is the final signon stage
|
||||
cls.signon = SIGNONS;
|
||||
CL_SignonReply();
|
||||
}
|
||||
|
||||
if (bits & U_MOREBITS) {
|
||||
i = MSG_ReadByte();
|
||||
bits |= (i << 8);
|
||||
}
|
||||
|
||||
if (bits & U_LONGENTITY)
|
||||
num = MSG_ReadShort();
|
||||
else
|
||||
num = MSG_ReadByte();
|
||||
|
||||
ent = CL_EntityNum(num);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (bits & (1 << i))
|
||||
bitcounts[i]++;
|
||||
|
||||
if (ent->msgtime != cl.mtime[1])
|
||||
forcelink = true; // no previous frame to lerp from
|
||||
else
|
||||
forcelink = false;
|
||||
|
||||
ent->msgtime = cl.mtime[0];
|
||||
|
||||
if (bits & U_MODEL) {
|
||||
modnum = MSG_ReadByte();
|
||||
if (modnum >= MAX_MODELS)
|
||||
Host_Error("CL_ParseModel: bad modnum");
|
||||
} else
|
||||
modnum = ent->baseline.modelindex;
|
||||
|
||||
model = cl.model_precache[modnum];
|
||||
if (model != ent->model) {
|
||||
ent->model = model;
|
||||
// automatic animation (torches, etc) can be either all together
|
||||
// or randomized
|
||||
if (model) {
|
||||
if (model->synctype == ST_RAND)
|
||||
ent->syncbase = (float)(rand() & 0x7fff) / 0x7fff;
|
||||
else
|
||||
ent->syncbase = 0.0;
|
||||
} else
|
||||
forcelink = true; // hack to make null model players work
|
||||
|
||||
#ifdef GLQUAKE
|
||||
if (num > 0 && num <= cl.maxclients)
|
||||
R_TranslatePlayerSkin(num - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (bits & U_FRAME)
|
||||
ent->frame = MSG_ReadByte();
|
||||
else
|
||||
ent->frame = ent->baseline.frame;
|
||||
|
||||
if (bits & U_COLORMAP)
|
||||
i = MSG_ReadByte();
|
||||
else
|
||||
i = ent->baseline.colormap;
|
||||
if (!i)
|
||||
ent->colormap = vid.colormap;
|
||||
else {
|
||||
if (i > cl.maxclients)
|
||||
Sys_Error("i >= cl.maxclients");
|
||||
ent->colormap = cl.scores[i - 1].translations;
|
||||
}
|
||||
|
||||
#ifdef GLQUAKE
|
||||
if (bits & U_SKIN)
|
||||
skin = MSG_ReadByte();
|
||||
else
|
||||
skin = ent->baseline.skinnum;
|
||||
if (skin != ent->skinnum) {
|
||||
ent->skinnum = skin;
|
||||
if (num > 0 && num <= cl.maxclients)
|
||||
R_TranslatePlayerSkin(num - 1);
|
||||
}
|
||||
#else
|
||||
|
||||
if (bits & U_SKIN)
|
||||
ent->skinnum = MSG_ReadByte();
|
||||
else
|
||||
ent->skinnum = ent->baseline.skinnum;
|
||||
#endif
|
||||
|
||||
if (bits & U_EFFECTS)
|
||||
ent->effects = MSG_ReadByte();
|
||||
else
|
||||
ent->effects = ent->baseline.effects;
|
||||
|
||||
// shift the known values for interpolation
|
||||
VectorCopy(ent->msg_origins[0], ent->msg_origins[1]);
|
||||
VectorCopy(ent->msg_angles[0], ent->msg_angles[1]);
|
||||
|
||||
if (bits & U_ORIGIN1)
|
||||
ent->msg_origins[0][0] = MSG_ReadCoord();
|
||||
else
|
||||
ent->msg_origins[0][0] = ent->baseline.origin[0];
|
||||
if (bits & U_ANGLE1)
|
||||
ent->msg_angles[0][0] = MSG_ReadAngle();
|
||||
else
|
||||
ent->msg_angles[0][0] = ent->baseline.angles[0];
|
||||
|
||||
if (bits & U_ORIGIN2)
|
||||
ent->msg_origins[0][1] = MSG_ReadCoord();
|
||||
else
|
||||
ent->msg_origins[0][1] = ent->baseline.origin[1];
|
||||
if (bits & U_ANGLE2)
|
||||
ent->msg_angles[0][1] = MSG_ReadAngle();
|
||||
else
|
||||
ent->msg_angles[0][1] = ent->baseline.angles[1];
|
||||
|
||||
if (bits & U_ORIGIN3)
|
||||
ent->msg_origins[0][2] = MSG_ReadCoord();
|
||||
else
|
||||
ent->msg_origins[0][2] = ent->baseline.origin[2];
|
||||
if (bits & U_ANGLE3)
|
||||
ent->msg_angles[0][2] = MSG_ReadAngle();
|
||||
else
|
||||
ent->msg_angles[0][2] = ent->baseline.angles[2];
|
||||
|
||||
if (bits & U_NOLERP)
|
||||
ent->forcelink = true;
|
||||
|
||||
if (forcelink) { // didn't have an update last message
|
||||
VectorCopy(ent->msg_origins[0], ent->msg_origins[1]);
|
||||
VectorCopy(ent->msg_origins[0], ent->origin);
|
||||
VectorCopy(ent->msg_angles[0], ent->msg_angles[1]);
|
||||
VectorCopy(ent->msg_angles[0], ent->angles);
|
||||
ent->forcelink = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseBaseline
|
||||
==================
|
||||
*/
|
||||
void
|
||||
CL_ParseBaseline(entity_t *ent)
|
||||
{
|
||||
int i;
|
||||
|
||||
ent->baseline.modelindex = MSG_ReadByte();
|
||||
ent->baseline.frame = MSG_ReadByte();
|
||||
ent->baseline.colormap = MSG_ReadByte();
|
||||
ent->baseline.skinnum = MSG_ReadByte();
|
||||
for (i = 0; i < 3; i++) {
|
||||
ent->baseline.origin[i] = MSG_ReadCoord();
|
||||
ent->baseline.angles[i] = MSG_ReadAngle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseClientdata
|
||||
|
||||
Server information pertaining to this client only
|
||||
==================
|
||||
*/
|
||||
void
|
||||
CL_ParseClientdata(int bits)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (bits & SU_VIEWHEIGHT)
|
||||
cl.viewheight = MSG_ReadChar();
|
||||
else
|
||||
cl.viewheight = DEFAULT_VIEWHEIGHT;
|
||||
|
||||
if (bits & SU_IDEALPITCH)
|
||||
cl.idealpitch = MSG_ReadChar();
|
||||
else
|
||||
cl.idealpitch = 0;
|
||||
|
||||
VectorCopy(cl.mvelocity[0], cl.mvelocity[1]);
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (bits & (SU_PUNCH1 << i))
|
||||
cl.punchangle[i] = MSG_ReadChar();
|
||||
else
|
||||
cl.punchangle[i] = 0;
|
||||
if (bits & (SU_VELOCITY1 << i))
|
||||
cl.mvelocity[0][i] = MSG_ReadChar() * 16;
|
||||
else
|
||||
cl.mvelocity[0][i] = 0;
|
||||
}
|
||||
|
||||
// [always sent] if (bits & SU_ITEMS)
|
||||
i = MSG_ReadLong();
|
||||
|
||||
if (cl.items != i) { // set flash times
|
||||
Sbar_Changed();
|
||||
for (j = 0; j < 32; j++)
|
||||
if ((i & (1 << j)) && !(cl.items & (1 << j)))
|
||||
cl.item_gettime[j] = cl.time;
|
||||
cl.items = i;
|
||||
}
|
||||
|
||||
cl.onground = (bits & SU_ONGROUND) != 0;
|
||||
cl.inwater = (bits & SU_INWATER) != 0;
|
||||
|
||||
if (bits & SU_WEAPONFRAME)
|
||||
cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte();
|
||||
else
|
||||
cl.stats[STAT_WEAPONFRAME] = 0;
|
||||
|
||||
if (bits & SU_ARMOR)
|
||||
i = MSG_ReadByte();
|
||||
else
|
||||
i = 0;
|
||||
if (cl.stats[STAT_ARMOR] != i) {
|
||||
cl.stats[STAT_ARMOR] = i;
|
||||
Sbar_Changed();
|
||||
}
|
||||
|
||||
if (bits & SU_WEAPON)
|
||||
i = MSG_ReadByte();
|
||||
else
|
||||
i = 0;
|
||||
if (cl.stats[STAT_WEAPON] != i) {
|
||||
cl.stats[STAT_WEAPON] = i;
|
||||
Sbar_Changed();
|
||||
}
|
||||
|
||||
i = MSG_ReadShort();
|
||||
if (cl.stats[STAT_HEALTH] != i) {
|
||||
cl.stats[STAT_HEALTH] = i;
|
||||
Sbar_Changed();
|
||||
}
|
||||
|
||||
i = MSG_ReadByte();
|
||||
if (cl.stats[STAT_AMMO] != i) {
|
||||
cl.stats[STAT_AMMO] = i;
|
||||
Sbar_Changed();
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
j = MSG_ReadByte();
|
||||
if (cl.stats[STAT_SHELLS + i] != j) {
|
||||
cl.stats[STAT_SHELLS + i] = j;
|
||||
Sbar_Changed();
|
||||
}
|
||||
}
|
||||
|
||||
i = MSG_ReadByte();
|
||||
|
||||
if (standard_quake) {
|
||||
if (cl.stats[STAT_ACTIVEWEAPON] != i) {
|
||||
cl.stats[STAT_ACTIVEWEAPON] = i;
|
||||
Sbar_Changed();
|
||||
}
|
||||
} else {
|
||||
if (cl.stats[STAT_ACTIVEWEAPON] != (1 << i)) {
|
||||
cl.stats[STAT_ACTIVEWEAPON] = (1 << i);
|
||||
Sbar_Changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_NewTranslation
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
CL_NewTranslation(int slot)
|
||||
{
|
||||
int i, j;
|
||||
int top, bottom;
|
||||
byte *dest, *source;
|
||||
|
||||
if (slot > cl.maxclients)
|
||||
Sys_Error("%s: slot > cl.maxclients", __func__);
|
||||
dest = cl.scores[slot].translations;
|
||||
source = vid.colormap;
|
||||
memcpy(dest, vid.colormap, sizeof(cl.scores[slot].translations));
|
||||
top = cl.scores[slot].colors & 0xf0;
|
||||
bottom = (cl.scores[slot].colors & 15) << 4;
|
||||
#ifdef GLQUAKE
|
||||
R_TranslatePlayerSkin(slot);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < VID_GRADES; i++, dest += 256, source += 256) {
|
||||
if (top < 128) // the artists made some backwards ranges. sigh.
|
||||
memcpy(dest + TOP_RANGE, source + top, 16);
|
||||
else
|
||||
for (j = 0; j < 16; j++)
|
||||
dest[TOP_RANGE + j] = source[top + 15 - j];
|
||||
|
||||
if (bottom < 128)
|
||||
memcpy(dest + BOTTOM_RANGE, source + bottom, 16);
|
||||
else
|
||||
for (j = 0; j < 16; j++)
|
||||
dest[BOTTOM_RANGE + j] = source[bottom + 15 - j];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_ParseStatic
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
CL_ParseStatic(void)
|
||||
{
|
||||
entity_t *ent;
|
||||
int i;
|
||||
|
||||
i = cl.num_statics;
|
||||
if (i >= MAX_STATIC_ENTITIES)
|
||||
Host_Error("Too many static entities");
|
||||
ent = &cl_static_entities[i];
|
||||
cl.num_statics++;
|
||||
CL_ParseBaseline(ent);
|
||||
|
||||
// copy it to the current state
|
||||
ent->model = cl.model_precache[ent->baseline.modelindex];
|
||||
ent->frame = ent->baseline.frame;
|
||||
ent->colormap = vid.colormap;
|
||||
ent->skinnum = ent->baseline.skinnum;
|
||||
ent->effects = ent->baseline.effects;
|
||||
|
||||
VectorCopy(ent->baseline.origin, ent->origin);
|
||||
VectorCopy(ent->baseline.angles, ent->angles);
|
||||
R_AddEfrags(ent);
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
CL_ParseStaticSound
|
||||
===================
|
||||
*/
|
||||
void
|
||||
CL_ParseStaticSound(void)
|
||||
{
|
||||
vec3_t org;
|
||||
int sound_num, vol, atten;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
org[i] = MSG_ReadCoord();
|
||||
sound_num = MSG_ReadByte();
|
||||
vol = MSG_ReadByte();
|
||||
atten = MSG_ReadByte();
|
||||
|
||||
S_StaticSound(cl.sound_precache[sound_num], org, vol, atten);
|
||||
}
|
||||
|
||||
|
||||
/* helper function (was a macro, hence the CAPS) */
|
||||
static void
|
||||
SHOWNET(char *msg)
|
||||
{
|
||||
if (cl_shownet.value == 2)
|
||||
Con_Printf("%3i:%s\n", msg_readcount - 1, msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_ParseServerMessage
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
CL_ParseServerMessage(void)
|
||||
{
|
||||
int cmd;
|
||||
int i;
|
||||
|
||||
//
|
||||
// if recording demos, copy the message out
|
||||
//
|
||||
if (cl_shownet.value == 1)
|
||||
Con_Printf("%i ", net_message.cursize);
|
||||
else if (cl_shownet.value == 2)
|
||||
Con_Printf("------------------\n");
|
||||
|
||||
cl.onground = false; // unless the server says otherwise
|
||||
//
|
||||
// parse the message
|
||||
//
|
||||
MSG_BeginReading();
|
||||
|
||||
while (1) {
|
||||
if (msg_badread)
|
||||
Host_Error("CL_ParseServerMessage: Bad server message");
|
||||
|
||||
cmd = MSG_ReadByte();
|
||||
|
||||
if (cmd == -1) {
|
||||
SHOWNET("END OF MESSAGE");
|
||||
return; // end of message
|
||||
}
|
||||
// if the high bit of the command byte is set, it is a fast update
|
||||
if (cmd & 128) {
|
||||
SHOWNET("fast update");
|
||||
CL_ParseUpdate(cmd & 127);
|
||||
continue;
|
||||
}
|
||||
|
||||
SHOWNET(svc_strings[cmd]);
|
||||
|
||||
// other commands
|
||||
switch (cmd) {
|
||||
default:
|
||||
Host_Error("CL_ParseServerMessage: Illegible server message");
|
||||
break;
|
||||
|
||||
case svc_nop:
|
||||
// Con_Printf ("svc_nop\n");
|
||||
break;
|
||||
|
||||
case svc_time:
|
||||
cl.mtime[1] = cl.mtime[0];
|
||||
cl.mtime[0] = MSG_ReadFloat();
|
||||
break;
|
||||
|
||||
case svc_clientdata:
|
||||
i = MSG_ReadShort();
|
||||
CL_ParseClientdata(i);
|
||||
break;
|
||||
|
||||
case svc_version:
|
||||
i = MSG_ReadLong();
|
||||
if (i != PROTOCOL_VERSION)
|
||||
Host_Error("CL_ParseServerMessage: "
|
||||
"Server is protocol %i instead of %i",
|
||||
i, PROTOCOL_VERSION);
|
||||
break;
|
||||
|
||||
case svc_disconnect:
|
||||
Host_EndGame("Server disconnected\n");
|
||||
|
||||
case svc_print:
|
||||
Con_Printf("%s", MSG_ReadString());
|
||||
break;
|
||||
|
||||
case svc_centerprint:
|
||||
SCR_CenterPrint(MSG_ReadString());
|
||||
break;
|
||||
|
||||
case svc_stufftext:
|
||||
Cbuf_AddText(MSG_ReadString());
|
||||
break;
|
||||
|
||||
case svc_damage:
|
||||
V_ParseDamage();
|
||||
break;
|
||||
|
||||
case svc_serverinfo:
|
||||
CL_ParseServerInfo();
|
||||
vid.recalc_refdef = true; // leave intermission full screen
|
||||
break;
|
||||
|
||||
case svc_setangle:
|
||||
for (i = 0; i < 3; i++)
|
||||
cl.viewangles[i] = MSG_ReadAngle();
|
||||
break;
|
||||
|
||||
case svc_setview:
|
||||
cl.viewentity = MSG_ReadShort();
|
||||
break;
|
||||
|
||||
case svc_lightstyle:
|
||||
i = MSG_ReadByte();
|
||||
if (i >= MAX_LIGHTSTYLES)
|
||||
Sys_Error("svc_lightstyle > MAX_LIGHTSTYLES");
|
||||
strcpy(cl_lightstyle[i].map, MSG_ReadString());
|
||||
cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
|
||||
break;
|
||||
|
||||
case svc_sound:
|
||||
CL_ParseStartSoundPacket();
|
||||
break;
|
||||
|
||||
case svc_stopsound:
|
||||
i = MSG_ReadShort();
|
||||
S_StopSound(i >> 3, i & 7);
|
||||
break;
|
||||
|
||||
case svc_updatename:
|
||||
Sbar_Changed();
|
||||
i = MSG_ReadByte();
|
||||
if (i >= cl.maxclients)
|
||||
Host_Error
|
||||
("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD");
|
||||
strcpy(cl.scores[i].name, MSG_ReadString());
|
||||
break;
|
||||
|
||||
case svc_updatefrags:
|
||||
Sbar_Changed();
|
||||
i = MSG_ReadByte();
|
||||
if (i >= cl.maxclients)
|
||||
Host_Error
|
||||
("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD");
|
||||
cl.scores[i].frags = MSG_ReadShort();
|
||||
break;
|
||||
|
||||
case svc_updatecolors:
|
||||
Sbar_Changed();
|
||||
i = MSG_ReadByte();
|
||||
if (i >= cl.maxclients)
|
||||
Host_Error
|
||||
("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD");
|
||||
cl.scores[i].colors = MSG_ReadByte();
|
||||
CL_NewTranslation(i);
|
||||
break;
|
||||
|
||||
case svc_particle:
|
||||
R_ParseParticleEffect();
|
||||
break;
|
||||
|
||||
case svc_spawnbaseline:
|
||||
i = MSG_ReadShort();
|
||||
// must use CL_EntityNum() to force cl.num_entities up
|
||||
CL_ParseBaseline(CL_EntityNum(i));
|
||||
break;
|
||||
case svc_spawnstatic:
|
||||
CL_ParseStatic();
|
||||
break;
|
||||
case svc_temp_entity:
|
||||
CL_ParseTEnt();
|
||||
break;
|
||||
|
||||
case svc_setpause:
|
||||
{
|
||||
cl.paused = MSG_ReadByte();
|
||||
|
||||
if (cl.paused) {
|
||||
CDAudio_Pause();
|
||||
#ifdef _WIN32
|
||||
VID_HandlePause(true);
|
||||
#endif
|
||||
} else {
|
||||
CDAudio_Resume();
|
||||
#ifdef _WIN32
|
||||
VID_HandlePause(false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case svc_signonnum:
|
||||
i = MSG_ReadByte();
|
||||
if (i <= cls.signon)
|
||||
Host_Error("Received signon %i when at %i", i, cls.signon);
|
||||
cls.signon = i;
|
||||
CL_SignonReply();
|
||||
break;
|
||||
|
||||
case svc_killedmonster:
|
||||
cl.stats[STAT_MONSTERS]++;
|
||||
break;
|
||||
|
||||
case svc_foundsecret:
|
||||
cl.stats[STAT_SECRETS]++;
|
||||
break;
|
||||
|
||||
case svc_updatestat:
|
||||
i = MSG_ReadByte();
|
||||
if (i < 0 || i >= MAX_CL_STATS)
|
||||
Sys_Error("svc_updatestat: %i is invalid", i);
|
||||
cl.stats[i] = MSG_ReadLong();;
|
||||
break;
|
||||
|
||||
case svc_spawnstaticsound:
|
||||
CL_ParseStaticSound();
|
||||
break;
|
||||
|
||||
case svc_cdtrack:
|
||||
cl.cdtrack = MSG_ReadByte();
|
||||
cl.looptrack = MSG_ReadByte();
|
||||
if ((cls.demoplayback || cls.demorecording)
|
||||
&& (cls.forcetrack != -1))
|
||||
CDAudio_Play((byte)cls.forcetrack, true);
|
||||
else
|
||||
CDAudio_Play((byte)cl.cdtrack, true);
|
||||
break;
|
||||
|
||||
case svc_intermission:
|
||||
cl.intermission = 1;
|
||||
cl.completed_time = cl.time;
|
||||
vid.recalc_refdef = true; // go to full screen
|
||||
break;
|
||||
|
||||
case svc_finale:
|
||||
cl.intermission = 2;
|
||||
cl.completed_time = cl.time;
|
||||
vid.recalc_refdef = true; // go to full screen
|
||||
SCR_CenterPrint(MSG_ReadString());
|
||||
break;
|
||||
|
||||
case svc_cutscene:
|
||||
cl.intermission = 3;
|
||||
cl.completed_time = cl.time;
|
||||
vid.recalc_refdef = true; // go to full screen
|
||||
SCR_CenterPrint(MSG_ReadString());
|
||||
break;
|
||||
|
||||
case svc_sellscreen:
|
||||
Cmd_ExecuteString("help", src_command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
355
NQ/cl_tent.c
Normal file
355
NQ/cl_tent.c
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cl_tent.c -- client side temporary entities
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "client.h"
|
||||
#include "sound.h"
|
||||
#include "protocol.h"
|
||||
#include "console.h"
|
||||
#include "sys.h"
|
||||
|
||||
#ifdef GLQUAKE
|
||||
# include "gl_model.h"
|
||||
#else
|
||||
# include "model.h"
|
||||
#endif
|
||||
|
||||
int num_temp_entities;
|
||||
entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
|
||||
beam_t cl_beams[MAX_BEAMS];
|
||||
|
||||
sfx_t *cl_sfx_wizhit;
|
||||
sfx_t *cl_sfx_knighthit;
|
||||
sfx_t *cl_sfx_tink1;
|
||||
sfx_t *cl_sfx_ric1;
|
||||
sfx_t *cl_sfx_ric2;
|
||||
sfx_t *cl_sfx_ric3;
|
||||
sfx_t *cl_sfx_r_exp3;
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_ParseTEnt
|
||||
=================
|
||||
*/
|
||||
void
|
||||
CL_InitTEnts(void)
|
||||
{
|
||||
cl_sfx_wizhit = S_PrecacheSound("wizard/hit.wav");
|
||||
cl_sfx_knighthit = S_PrecacheSound("hknight/hit.wav");
|
||||
cl_sfx_tink1 = S_PrecacheSound("weapons/tink1.wav");
|
||||
cl_sfx_ric1 = S_PrecacheSound("weapons/ric1.wav");
|
||||
cl_sfx_ric2 = S_PrecacheSound("weapons/ric2.wav");
|
||||
cl_sfx_ric3 = S_PrecacheSound("weapons/ric3.wav");
|
||||
cl_sfx_r_exp3 = S_PrecacheSound("weapons/r_exp3.wav");
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_ParseBeam
|
||||
=================
|
||||
*/
|
||||
void
|
||||
CL_ParseBeam(model_t *m)
|
||||
{
|
||||
int ent;
|
||||
vec3_t start, end;
|
||||
beam_t *b;
|
||||
int i;
|
||||
|
||||
ent = MSG_ReadShort();
|
||||
|
||||
start[0] = MSG_ReadCoord();
|
||||
start[1] = MSG_ReadCoord();
|
||||
start[2] = MSG_ReadCoord();
|
||||
|
||||
end[0] = MSG_ReadCoord();
|
||||
end[1] = MSG_ReadCoord();
|
||||
end[2] = MSG_ReadCoord();
|
||||
|
||||
// override any beam with the same entity
|
||||
for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++)
|
||||
if (b->entity == ent) {
|
||||
b->entity = ent;
|
||||
b->model = m;
|
||||
b->endtime = cl.time + 0.2;
|
||||
VectorCopy(start, b->start);
|
||||
VectorCopy(end, b->end);
|
||||
return;
|
||||
}
|
||||
// find a free beam
|
||||
for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) {
|
||||
if (!b->model || b->endtime < cl.time) {
|
||||
b->entity = ent;
|
||||
b->model = m;
|
||||
b->endtime = cl.time + 0.2;
|
||||
VectorCopy(start, b->start);
|
||||
VectorCopy(end, b->end);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Con_Printf("beam list overflow!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_ParseTEnt
|
||||
=================
|
||||
*/
|
||||
void
|
||||
CL_ParseTEnt(void)
|
||||
{
|
||||
int type;
|
||||
vec3_t pos;
|
||||
|
||||
dlight_t *dl;
|
||||
int rnd;
|
||||
int colorStart, colorLength;
|
||||
|
||||
type = MSG_ReadByte();
|
||||
switch (type) {
|
||||
case TE_WIZSPIKE: // spike hitting wall
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
R_RunParticleEffect(pos, vec3_origin, 20, 30);
|
||||
S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
|
||||
break;
|
||||
|
||||
case TE_KNIGHTSPIKE: // spike hitting wall
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
R_RunParticleEffect(pos, vec3_origin, 226, 20);
|
||||
S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
|
||||
break;
|
||||
|
||||
case TE_SPIKE: // spike hitting wall
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
|
||||
R_RunParticleEffect(pos, vec3_origin, 0, 10);
|
||||
|
||||
if (rand() % 5)
|
||||
S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
|
||||
else {
|
||||
rnd = rand() & 3;
|
||||
if (rnd == 1)
|
||||
S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
|
||||
else if (rnd == 2)
|
||||
S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
|
||||
else
|
||||
S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
|
||||
}
|
||||
break;
|
||||
case TE_SUPERSPIKE: // super spike hitting wall
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
R_RunParticleEffect(pos, vec3_origin, 0, 20);
|
||||
|
||||
if (rand() % 5)
|
||||
S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
|
||||
else {
|
||||
rnd = rand() & 3;
|
||||
if (rnd == 1)
|
||||
S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
|
||||
else if (rnd == 2)
|
||||
S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
|
||||
else
|
||||
S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case TE_GUNSHOT: // bullet hitting wall
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
R_RunParticleEffect(pos, vec3_origin, 0, 20);
|
||||
break;
|
||||
|
||||
case TE_EXPLOSION: // rocket explosion
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
R_ParticleExplosion(pos);
|
||||
dl = CL_AllocDlight(0);
|
||||
VectorCopy(pos, dl->origin);
|
||||
dl->radius = 350;
|
||||
dl->die = cl.time + 0.5;
|
||||
dl->decay = 300;
|
||||
S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
||||
break;
|
||||
|
||||
case TE_TAREXPLOSION: // tarbaby explosion
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
R_BlobExplosion(pos);
|
||||
|
||||
S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
||||
break;
|
||||
|
||||
case TE_LIGHTNING1: // lightning bolts
|
||||
CL_ParseBeam(Mod_ForName("progs/bolt.mdl", true));
|
||||
break;
|
||||
|
||||
case TE_LIGHTNING2: // lightning bolts
|
||||
CL_ParseBeam(Mod_ForName("progs/bolt2.mdl", true));
|
||||
break;
|
||||
|
||||
case TE_LIGHTNING3: // lightning bolts
|
||||
CL_ParseBeam(Mod_ForName("progs/bolt3.mdl", true));
|
||||
break;
|
||||
|
||||
// PGM 01/21/97
|
||||
case TE_BEAM: // grappling hook beam
|
||||
CL_ParseBeam(Mod_ForName("progs/beam.mdl", true));
|
||||
break;
|
||||
// PGM 01/21/97
|
||||
|
||||
case TE_LAVASPLASH:
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
R_LavaSplash(pos);
|
||||
break;
|
||||
|
||||
case TE_TELEPORT:
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
R_TeleportSplash(pos);
|
||||
break;
|
||||
|
||||
case TE_EXPLOSION2: // color mapped explosion
|
||||
pos[0] = MSG_ReadCoord();
|
||||
pos[1] = MSG_ReadCoord();
|
||||
pos[2] = MSG_ReadCoord();
|
||||
colorStart = MSG_ReadByte();
|
||||
colorLength = MSG_ReadByte();
|
||||
R_ParticleExplosion2(pos, colorStart, colorLength);
|
||||
dl = CL_AllocDlight(0);
|
||||
VectorCopy(pos, dl->origin);
|
||||
dl->radius = 350;
|
||||
dl->die = cl.time + 0.5;
|
||||
dl->decay = 300;
|
||||
S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
Sys_Error("%s: bad type", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_NewTempEntity
|
||||
=================
|
||||
*/
|
||||
entity_t *
|
||||
CL_NewTempEntity(void)
|
||||
{
|
||||
entity_t *ent;
|
||||
|
||||
if (cl_numvisedicts == MAX_VISEDICTS)
|
||||
return NULL;
|
||||
if (num_temp_entities == MAX_TEMP_ENTITIES)
|
||||
return NULL;
|
||||
ent = &cl_temp_entities[num_temp_entities];
|
||||
memset(ent, 0, sizeof(*ent));
|
||||
num_temp_entities++;
|
||||
cl_visedicts[cl_numvisedicts] = ent;
|
||||
cl_numvisedicts++;
|
||||
|
||||
ent->colormap = vid.colormap;
|
||||
return ent;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_UpdateTEnts
|
||||
=================
|
||||
*/
|
||||
void
|
||||
CL_UpdateTEnts(void)
|
||||
{
|
||||
int i;
|
||||
beam_t *b;
|
||||
vec3_t dist, org;
|
||||
float d;
|
||||
entity_t *ent;
|
||||
float yaw, pitch;
|
||||
float forward;
|
||||
|
||||
num_temp_entities = 0;
|
||||
|
||||
// update lightning
|
||||
for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) {
|
||||
if (!b->model || b->endtime < cl.time)
|
||||
continue;
|
||||
|
||||
// if coming from the player, update the start position
|
||||
if (b->entity == cl.viewentity) {
|
||||
VectorCopy(cl_entities[cl.viewentity].origin, b->start);
|
||||
}
|
||||
// calculate pitch and yaw
|
||||
VectorSubtract(b->end, b->start, dist);
|
||||
|
||||
if (dist[1] == 0 && dist[0] == 0) {
|
||||
yaw = 0;
|
||||
if (dist[2] > 0)
|
||||
pitch = 90;
|
||||
else
|
||||
pitch = 270;
|
||||
} else {
|
||||
yaw = (int)(atan2(dist[1], dist[0]) * 180 / M_PI);
|
||||
if (yaw < 0)
|
||||
yaw += 360;
|
||||
|
||||
forward = sqrt(dist[0] * dist[0] + dist[1] * dist[1]);
|
||||
pitch = (int)(atan2(dist[2], forward) * 180 / M_PI);
|
||||
if (pitch < 0)
|
||||
pitch += 360;
|
||||
}
|
||||
|
||||
// add new entities for the lightning
|
||||
VectorCopy(b->start, org);
|
||||
d = VectorNormalize(dist);
|
||||
while (d > 0) {
|
||||
ent = CL_NewTempEntity();
|
||||
if (!ent)
|
||||
return;
|
||||
VectorCopy(org, ent->origin);
|
||||
ent->model = b->model;
|
||||
ent->angles[0] = pitch;
|
||||
ent->angles[1] = yaw;
|
||||
ent->angles[2] = rand() % 360;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
org[i] += dist[i] * 30;
|
||||
d -= 30;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
359
NQ/client.h
Normal file
359
NQ/client.h
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_H
|
||||
#define CLIENT_H
|
||||
|
||||
#include "common.h"
|
||||
#include "mathlib.h"
|
||||
#include "quakedef.h"
|
||||
#include "render.h"
|
||||
#include "vid.h"
|
||||
|
||||
//
|
||||
// client_state_t should hold all pieces of the client state
|
||||
//
|
||||
|
||||
typedef struct {
|
||||
vec3_t viewangles;
|
||||
|
||||
// intended velocities
|
||||
float forwardmove;
|
||||
float sidemove;
|
||||
float upmove;
|
||||
} usercmd_t;
|
||||
|
||||
#define MAX_DLIGHTS 32
|
||||
typedef struct {
|
||||
int key; // so entities can reuse same entry
|
||||
vec3_t origin;
|
||||
float radius;
|
||||
float die; // stop lighting after this time
|
||||
float decay; // drop this each second
|
||||
float minlight; // don't add when contributing less
|
||||
} dlight_t;
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
char map[MAX_STYLESTRING];
|
||||
} lightstyle_t;
|
||||
|
||||
#define MAX_SCOREBOARDNAME 32
|
||||
typedef struct {
|
||||
char name[MAX_SCOREBOARDNAME];
|
||||
float entertime;
|
||||
int frags;
|
||||
int colors; // two 4 bit fields
|
||||
byte translations[VID_GRADES * 256];
|
||||
} scoreboard_t;
|
||||
|
||||
typedef struct {
|
||||
int destcolor[3];
|
||||
int percent; // 0-256
|
||||
} cshift_t;
|
||||
|
||||
#define CSHIFT_CONTENTS 0
|
||||
#define CSHIFT_DAMAGE 1
|
||||
#define CSHIFT_BONUS 2
|
||||
#define CSHIFT_POWERUP 3
|
||||
|
||||
#define NUM_CSHIFTS 4
|
||||
|
||||
#define MAX_BEAMS 24
|
||||
typedef struct {
|
||||
int entity;
|
||||
struct model_s *model;
|
||||
float endtime;
|
||||
vec3_t start, end;
|
||||
} beam_t;
|
||||
|
||||
#define MAX_EFRAGS 640
|
||||
|
||||
#define MAX_MAPSTRING 2048
|
||||
#define MAX_DEMOS 8
|
||||
#define MAX_DEMONAME 16
|
||||
|
||||
#define SIGNONS 4 // signon messages to receive before connected
|
||||
typedef enum {
|
||||
ca_dedicated, // a dedicated server with no ability to start a client
|
||||
ca_disconnected, // full screen console with no connection
|
||||
ca_connected, // valid netcon, doing signons...
|
||||
ca_firstupdate, // waiting for first update (final signon stage)
|
||||
ca_active // signons complete, frames can be rendered
|
||||
} cactive_t;
|
||||
|
||||
//
|
||||
// the client_static_t structure is persistant through an arbitrary number
|
||||
// of server connections
|
||||
//
|
||||
typedef struct {
|
||||
cactive_t state;
|
||||
|
||||
// personalization data sent to server
|
||||
char mapstring[MAX_QPATH];
|
||||
char spawnparms[MAX_MAPSTRING]; // to restart a level
|
||||
|
||||
// demo loop control
|
||||
int demonum; // -1 = don't play demos
|
||||
char demos[MAX_DEMOS][MAX_DEMONAME]; // when not playing
|
||||
|
||||
// demo recording info must be here, because record is started before
|
||||
// entering a map (and clearing client_state_t)
|
||||
qboolean demorecording;
|
||||
qboolean demoplayback;
|
||||
qboolean timedemo;
|
||||
int forcetrack; // -1 = use normal cd track
|
||||
FILE *demofile;
|
||||
int td_lastframe; // to meter out one message a frame
|
||||
int td_startframe; // host_framecount at start
|
||||
float td_starttime; // realtime at second frame of timedemo
|
||||
|
||||
// connection information
|
||||
int signon; // 0 to SIGNONS
|
||||
struct qsocket_s *netcon;
|
||||
sizebuf_t message; // writing buffer to send to server
|
||||
|
||||
} client_static_t;
|
||||
|
||||
extern client_static_t cls;
|
||||
|
||||
//
|
||||
// the client_state_t structure is wiped completely at every
|
||||
// server signon
|
||||
//
|
||||
typedef struct {
|
||||
int movemessages; // since connecting to this server
|
||||
// throw out the first couple, so the player
|
||||
// doesn't accidentally do something the
|
||||
// first frame
|
||||
usercmd_t cmd; // last command sent to the server
|
||||
|
||||
// information for local display
|
||||
int stats[MAX_CL_STATS]; // health, etc
|
||||
int items; // inventory bit flags
|
||||
float item_gettime[32]; // cl.time of aquiring item, for blinking
|
||||
float faceanimtime; // use anim frame if cl.time < this
|
||||
|
||||
cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups
|
||||
cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types
|
||||
|
||||
// the client maintains its own idea of view angles, which are
|
||||
// sent to the server each frame. The server sets punchangle when
|
||||
// the view is temporarliy offset, and an angle reset commands at the start
|
||||
// of each level and after teleporting.
|
||||
vec3_t mviewangles[2]; // during demo playback viewangles is lerped
|
||||
// between these
|
||||
vec3_t viewangles;
|
||||
|
||||
vec3_t mvelocity[2]; // update by server, used for lean+bob
|
||||
// (0 is newest)
|
||||
vec3_t velocity; // lerped between mvelocity[0] and [1]
|
||||
|
||||
vec3_t punchangle; // temporary offset
|
||||
|
||||
// pitch drifting vars
|
||||
float idealpitch;
|
||||
float pitchvel;
|
||||
qboolean nodrift;
|
||||
float driftmove;
|
||||
double laststop;
|
||||
|
||||
float viewheight;
|
||||
float crouch; // local amount for smoothing stepups
|
||||
|
||||
qboolean paused; // send over by server
|
||||
qboolean onground;
|
||||
qboolean inwater;
|
||||
|
||||
int intermission; // don't change view angle, full screen, etc
|
||||
int completed_time; // latched at intermission start
|
||||
|
||||
double mtime[2]; // the timestamp of last two messages
|
||||
double time; // clients view of time, should be between
|
||||
// servertime and oldservertime to generate
|
||||
// a lerp point for other data
|
||||
double oldtime; // previous cl.time, time-oldtime is used
|
||||
// to decay light values and smooth step ups
|
||||
|
||||
float last_received_message; // (realtime) for net trouble icon
|
||||
|
||||
//
|
||||
// information that is static for the entire time connected to a server
|
||||
//
|
||||
struct model_s *model_precache[MAX_MODELS];
|
||||
struct sfx_s *sound_precache[MAX_SOUNDS];
|
||||
|
||||
char levelname[40]; // for display on solo scoreboard
|
||||
int viewentity; // cl_entitites[cl.viewentity] = player
|
||||
int maxclients;
|
||||
int gametype;
|
||||
|
||||
// refresh related state
|
||||
struct model_s *worldmodel; // cl_entitites[0].model
|
||||
struct efrag_s *free_efrags;
|
||||
int num_entities; // held in cl_entities array
|
||||
int num_statics; // held in cl_staticentities array
|
||||
entity_t viewent; // the gun model
|
||||
|
||||
int cdtrack, looptrack; // cd audio
|
||||
|
||||
// frag scoreboard
|
||||
scoreboard_t *scores; // [cl.maxclients]
|
||||
|
||||
} client_state_t;
|
||||
|
||||
|
||||
//
|
||||
// cvars
|
||||
//
|
||||
extern cvar_t cl_name;
|
||||
extern cvar_t cl_color;
|
||||
|
||||
extern cvar_t cl_upspeed;
|
||||
extern cvar_t cl_forwardspeed;
|
||||
extern cvar_t cl_backspeed;
|
||||
extern cvar_t cl_sidespeed;
|
||||
|
||||
extern cvar_t cl_movespeedkey;
|
||||
|
||||
extern cvar_t cl_yawspeed;
|
||||
extern cvar_t cl_pitchspeed;
|
||||
|
||||
extern cvar_t cl_anglespeedkey;
|
||||
|
||||
extern cvar_t cl_autofire;
|
||||
|
||||
extern cvar_t cl_shownet;
|
||||
extern cvar_t cl_nolerp;
|
||||
|
||||
extern cvar_t cl_pitchdriftspeed;
|
||||
extern cvar_t lookspring;
|
||||
extern cvar_t lookstrafe;
|
||||
extern cvar_t sensitivity;
|
||||
|
||||
extern cvar_t m_pitch;
|
||||
extern cvar_t m_yaw;
|
||||
extern cvar_t m_forward;
|
||||
extern cvar_t m_side;
|
||||
|
||||
|
||||
#define MAX_TEMP_ENTITIES 64 // lightning bolts, etc
|
||||
#define MAX_STATIC_ENTITIES 128 // torches, etc
|
||||
|
||||
extern client_state_t cl;
|
||||
|
||||
// FIXME, allocate dynamically
|
||||
extern efrag_t cl_efrags[MAX_EFRAGS];
|
||||
extern entity_t cl_entities[MAX_EDICTS];
|
||||
extern entity_t cl_static_entities[MAX_STATIC_ENTITIES];
|
||||
extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
|
||||
extern dlight_t cl_dlights[MAX_DLIGHTS];
|
||||
extern entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
|
||||
extern beam_t cl_beams[MAX_BEAMS];
|
||||
|
||||
//=============================================================================
|
||||
|
||||
//
|
||||
// cl_main
|
||||
//
|
||||
dlight_t *CL_AllocDlight(int key);
|
||||
void CL_DecayLights(void);
|
||||
|
||||
void CL_Init(void);
|
||||
|
||||
void CL_EstablishConnection(char *host);
|
||||
void CL_Signon1(void);
|
||||
void CL_Signon2(void);
|
||||
void CL_Signon3(void);
|
||||
void CL_Signon4(void);
|
||||
|
||||
void CL_Disconnect(void);
|
||||
void CL_Disconnect_f(void);
|
||||
void CL_NextDemo(void);
|
||||
|
||||
#define MAX_VISEDICTS 256
|
||||
extern int cl_numvisedicts;
|
||||
extern entity_t *cl_visedicts[MAX_VISEDICTS];
|
||||
|
||||
//
|
||||
// cl_input
|
||||
//
|
||||
typedef struct {
|
||||
int down[2]; // key nums holding it down
|
||||
int state; // low bit is down state
|
||||
} kbutton_t;
|
||||
|
||||
extern kbutton_t in_mlook, in_klook;
|
||||
extern kbutton_t in_strafe;
|
||||
extern kbutton_t in_speed;
|
||||
|
||||
void CL_InitInput(void);
|
||||
void CL_SendCmd(void);
|
||||
void CL_SendMove(usercmd_t *cmd);
|
||||
|
||||
void CL_ParseTEnt(void);
|
||||
void CL_UpdateTEnts(void);
|
||||
|
||||
void CL_ClearState(void);
|
||||
|
||||
|
||||
int CL_ReadFromServer(void);
|
||||
void CL_WriteToServer(usercmd_t *cmd);
|
||||
void CL_BaseMove(usercmd_t *cmd);
|
||||
|
||||
|
||||
char *Key_KeynumToString(int keynum);
|
||||
|
||||
//
|
||||
// cl_demo.c
|
||||
//
|
||||
void CL_StopPlayback(void);
|
||||
int CL_GetMessage(void);
|
||||
|
||||
void CL_Stop_f(void);
|
||||
void CL_Record_f(void);
|
||||
void CL_PlayDemo_f(void);
|
||||
void CL_TimeDemo_f(void);
|
||||
|
||||
//
|
||||
// cl_parse.c
|
||||
//
|
||||
void CL_ParseServerMessage(void);
|
||||
|
||||
//
|
||||
// view.c
|
||||
//
|
||||
void V_StartPitchDrift(void);
|
||||
void V_StopPitchDrift(void);
|
||||
|
||||
void V_RenderView(void);
|
||||
void V_UpdatePalette(void);
|
||||
void V_Register(void);
|
||||
void V_ParseDamage(void);
|
||||
void V_SetContentsColor(int contents);
|
||||
|
||||
|
||||
//
|
||||
// cl_tent
|
||||
//
|
||||
void CL_InitTEnts(void);
|
||||
void CL_SignonReply(void);
|
||||
|
||||
#endif /* CLIENT_H */
|
673
NQ/cmd.c
Normal file
673
NQ/cmd.c
Normal file
@ -0,0 +1,673 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cmd.c -- Quake script command processing module
|
||||
|
||||
#include "client.h"
|
||||
#include "cmd.h"
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "host.h"
|
||||
#include "protocol.h"
|
||||
#include "quakedef.h"
|
||||
#include "shell.h"
|
||||
#include "sys.h"
|
||||
#include "zone.h"
|
||||
|
||||
void Cmd_ForwardToServer(void);
|
||||
|
||||
#define MAX_ALIAS_NAME 32
|
||||
|
||||
typedef struct cmdalias_s {
|
||||
struct cmdalias_s *next;
|
||||
char name[MAX_ALIAS_NAME];
|
||||
char *value;
|
||||
} cmdalias_t;
|
||||
|
||||
cmdalias_t *cmd_alias;
|
||||
|
||||
qboolean cmd_wait;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Wait_f
|
||||
|
||||
Causes execution of the remainder of the command buffer to be delayed until
|
||||
next frame. This allows commands like:
|
||||
bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cmd_Wait_f(void)
|
||||
{
|
||||
cmd_wait = true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
COMMAND BUFFER
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
static sizebuf_t cmd_text;
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_Init
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cbuf_Init(void)
|
||||
{
|
||||
SZ_Alloc(&cmd_text, 8192); // space for commands and script files
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_AddText
|
||||
|
||||
Adds command text at the end of the buffer
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cbuf_AddText(char *text)
|
||||
{
|
||||
int l = strlen(text);
|
||||
|
||||
if (cmd_text.cursize + l < cmd_text.maxsize)
|
||||
SZ_Write(&cmd_text, text, l);
|
||||
else
|
||||
Con_Printf("Cbuf_AddText: overflow\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_InsertText
|
||||
|
||||
Adds command text immediately after the current command
|
||||
Adds a \n to the text
|
||||
FIXME: actually change the command buffer to do less copying
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cbuf_InsertText(char *text)
|
||||
{
|
||||
char *temp;
|
||||
int templen;
|
||||
|
||||
// copy off any commands still remaining in the exec buffer
|
||||
templen = cmd_text.cursize;
|
||||
if (templen) {
|
||||
temp = Z_Malloc(templen);
|
||||
memcpy(temp, cmd_text.data, templen);
|
||||
SZ_Clear(&cmd_text);
|
||||
} else
|
||||
temp = NULL; // shut up compiler
|
||||
|
||||
// add the entire text of the file
|
||||
Cbuf_AddText(text);
|
||||
SZ_Write(&cmd_text, "\n", 1);
|
||||
|
||||
// add the copied off data
|
||||
if (templen) {
|
||||
SZ_Write(&cmd_text, temp, templen);
|
||||
Z_Free(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_Execute
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cbuf_Execute(void)
|
||||
{
|
||||
int i;
|
||||
char *text;
|
||||
char line[1024];
|
||||
int quotes;
|
||||
|
||||
while (cmd_text.cursize) {
|
||||
/* find a \n or ; line break */
|
||||
text = (char *)cmd_text.data;
|
||||
|
||||
quotes = 0;
|
||||
for (i = 0; i < cmd_text.cursize; i++) {
|
||||
if (text[i] == '"')
|
||||
quotes++;
|
||||
if (!(quotes & 1) && text[i] == ';')
|
||||
break; /* don't break if inside a quoted string */
|
||||
if (text[i] == '\n')
|
||||
break;
|
||||
}
|
||||
memcpy(line, text, i);
|
||||
line[i] = 0;
|
||||
|
||||
/*
|
||||
* delete the text from the command buffer and move remaining commands
|
||||
* down this is necessary because commands (exec, alias) can insert
|
||||
* data at the beginning of the text buffer
|
||||
*/
|
||||
if (i == cmd_text.cursize)
|
||||
cmd_text.cursize = 0;
|
||||
else {
|
||||
i++;
|
||||
cmd_text.cursize -= i;
|
||||
memcpy(text, text + i, cmd_text.cursize);
|
||||
}
|
||||
|
||||
/* execute the command line */
|
||||
Cmd_ExecuteString(line, src_command);
|
||||
|
||||
if (cmd_wait) {
|
||||
/*
|
||||
* skip out while text still remains in buffer, leaving it for
|
||||
* next frame
|
||||
*/
|
||||
cmd_wait = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
SCRIPT COMMANDS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_StuffCmds_f
|
||||
|
||||
Adds command line parameters as script statements
|
||||
Commands lead with a +, and continue until a - or another +
|
||||
quake +prog jctest.qp +cmd amlev1
|
||||
quake -nosound +cmd amlev1
|
||||
===============
|
||||
*/
|
||||
void
|
||||
Cmd_StuffCmds_f(void)
|
||||
{
|
||||
int i, j;
|
||||
int s;
|
||||
char *text, *build, c;
|
||||
|
||||
if (Cmd_Argc() != 1) {
|
||||
Con_Printf("stuffcmds : execute command line parameters\n");
|
||||
return;
|
||||
}
|
||||
// build the combined string to parse from
|
||||
s = 0;
|
||||
for (i = 1; i < com_argc; i++) {
|
||||
if (!com_argv[i])
|
||||
continue; // NEXTSTEP nulls out -NXHost
|
||||
s += strlen(com_argv[i]) + 1;
|
||||
}
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
text = Z_Malloc(s + 1);
|
||||
text[0] = 0;
|
||||
for (i = 1; i < com_argc; i++) {
|
||||
if (!com_argv[i])
|
||||
continue; // NEXTSTEP nulls out -NXHost
|
||||
strcat(text, com_argv[i]);
|
||||
if (i != com_argc - 1)
|
||||
strcat(text, " ");
|
||||
}
|
||||
|
||||
// pull out the commands
|
||||
build = Z_Malloc(s + 1);
|
||||
build[0] = 0;
|
||||
|
||||
for (i = 0; i < s - 1; i++) {
|
||||
if (text[i] == '+') {
|
||||
i++;
|
||||
|
||||
for (j = i;
|
||||
(text[j] != '+') && (text[j] != '-') && (text[j] != 0); j++);
|
||||
|
||||
c = text[j];
|
||||
text[j] = 0;
|
||||
|
||||
strcat(build, text + i);
|
||||
strcat(build, "\n");
|
||||
text[j] = c;
|
||||
i = j - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (build[0])
|
||||
Cbuf_InsertText(build);
|
||||
|
||||
Z_Free(text);
|
||||
Z_Free(build);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Exec_f
|
||||
===============
|
||||
*/
|
||||
void
|
||||
Cmd_Exec_f(void)
|
||||
{
|
||||
char *f;
|
||||
int mark;
|
||||
|
||||
if (Cmd_Argc() != 2) {
|
||||
Con_Printf("exec <filename> : execute a script file\n");
|
||||
return;
|
||||
}
|
||||
// FIXME: is this safe freeing the hunk here???
|
||||
mark = Hunk_LowMark();
|
||||
f = (char *)COM_LoadHunkFile(Cmd_Argv(1));
|
||||
if (!f) {
|
||||
Con_Printf("couldn't exec %s\n", Cmd_Argv(1));
|
||||
return;
|
||||
}
|
||||
Con_Printf("execing %s\n", Cmd_Argv(1));
|
||||
|
||||
Cbuf_InsertText(f);
|
||||
Hunk_FreeToLowMark(mark);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Echo_f
|
||||
|
||||
Just prints the rest of the line to the console
|
||||
===============
|
||||
*/
|
||||
void
|
||||
Cmd_Echo_f(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < Cmd_Argc(); i++)
|
||||
Con_Printf("%s ", Cmd_Argv(i));
|
||||
Con_Printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Alias_f
|
||||
|
||||
Creates a new command that executes a command string (possibly ; seperated)
|
||||
===============
|
||||
*/
|
||||
|
||||
char *
|
||||
CopyString(char *in)
|
||||
{
|
||||
char *out;
|
||||
|
||||
out = Z_Malloc(strlen(in) + 1);
|
||||
strcpy(out, in);
|
||||
return out;
|
||||
}
|
||||
|
||||
void
|
||||
Cmd_Alias_f(void)
|
||||
{
|
||||
cmdalias_t *a;
|
||||
char cmd[1024];
|
||||
int i, c;
|
||||
char *s;
|
||||
|
||||
if (Cmd_Argc() == 1) {
|
||||
Con_Printf("Current alias commands:\n");
|
||||
for (a = cmd_alias; a; a = a->next)
|
||||
Con_Printf("%s : %s\n", a->name, a->value);
|
||||
return;
|
||||
}
|
||||
|
||||
s = Cmd_Argv(1);
|
||||
if (strlen(s) >= MAX_ALIAS_NAME) {
|
||||
Con_Printf("Alias name is too long\n");
|
||||
return;
|
||||
}
|
||||
// if the alias already exists, reuse it
|
||||
for (a = cmd_alias; a; a = a->next) {
|
||||
if (!strcmp(s, a->name)) {
|
||||
Z_Free(a->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!a) {
|
||||
a = Z_Malloc(sizeof(cmdalias_t));
|
||||
a->next = cmd_alias;
|
||||
cmd_alias = a;
|
||||
strcpy(a->name, s);
|
||||
insert_alias_completion(a->name);
|
||||
}
|
||||
|
||||
// copy the rest of the command line
|
||||
cmd[0] = 0; // start out with a null string
|
||||
c = Cmd_Argc();
|
||||
for (i = 2; i < c; i++) {
|
||||
strcat(cmd, Cmd_Argv(i));
|
||||
if (i != c)
|
||||
strcat(cmd, " ");
|
||||
}
|
||||
strcat(cmd, "\n");
|
||||
|
||||
a->value = CopyString(cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
COMMAND EXECUTION
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
typedef struct cmd_function_s {
|
||||
struct cmd_function_s *next;
|
||||
char *name;
|
||||
xcommand_t function;
|
||||
} cmd_function_t;
|
||||
|
||||
|
||||
#define MAX_ARGS 80
|
||||
|
||||
static int cmd_argc;
|
||||
static char *cmd_argv[MAX_ARGS];
|
||||
static char *cmd_null_string = "";
|
||||
static char *cmd_args = NULL;
|
||||
|
||||
cmd_source_t cmd_source;
|
||||
|
||||
static cmd_function_t *cmd_functions; // possible commands to execute
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Init
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cmd_Init(void)
|
||||
{
|
||||
//
|
||||
// register our commands
|
||||
//
|
||||
Cmd_AddCommand("stuffcmds", Cmd_StuffCmds_f);
|
||||
Cmd_AddCommand("exec", Cmd_Exec_f);
|
||||
Cmd_AddCommand("echo", Cmd_Echo_f);
|
||||
Cmd_AddCommand("alias", Cmd_Alias_f);
|
||||
Cmd_AddCommand("cmd", Cmd_ForwardToServer);
|
||||
Cmd_AddCommand("wait", Cmd_Wait_f);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Argc
|
||||
============
|
||||
*/
|
||||
int
|
||||
Cmd_Argc(void)
|
||||
{
|
||||
return cmd_argc;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Argv
|
||||
============
|
||||
*/
|
||||
char *
|
||||
Cmd_Argv(int arg)
|
||||
{
|
||||
if (arg >= cmd_argc)
|
||||
return cmd_null_string;
|
||||
return cmd_argv[arg];
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Args
|
||||
|
||||
Returns a single string containing argv(1) to argv(argc()-1)
|
||||
============
|
||||
*/
|
||||
char *
|
||||
Cmd_Args(void)
|
||||
{
|
||||
// FIXME - check necessary?
|
||||
if (!cmd_args)
|
||||
return "";
|
||||
return cmd_args;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_TokenizeString
|
||||
|
||||
Parses the given string into command line tokens.
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cmd_TokenizeString(char *text)
|
||||
{
|
||||
int i;
|
||||
|
||||
// clear the args from the last string
|
||||
for (i = 0; i < cmd_argc; i++)
|
||||
Z_Free(cmd_argv[i]);
|
||||
|
||||
cmd_argc = 0;
|
||||
cmd_args = NULL;
|
||||
|
||||
while (1) {
|
||||
// skip whitespace up to a /n
|
||||
while (*text && *text <= ' ' && *text != '\n') {
|
||||
text++;
|
||||
}
|
||||
|
||||
if (*text == '\n') { // a newline seperates commands in the buffer
|
||||
text++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!*text)
|
||||
return;
|
||||
|
||||
if (cmd_argc == 1)
|
||||
cmd_args = text;
|
||||
|
||||
text = COM_Parse(text);
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
if (cmd_argc < MAX_ARGS) {
|
||||
cmd_argv[cmd_argc] = Z_Malloc(strlen(com_token) + 1);
|
||||
strcpy(cmd_argv[cmd_argc], com_token);
|
||||
cmd_argc++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_AddCommand
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cmd_AddCommand(char *cmd_name, xcommand_t function)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
|
||||
if (host_initialized) // because hunk allocation would get stomped
|
||||
Sys_Error("%s: called after host_initialized", __func__);
|
||||
|
||||
// fail if the command is a variable name
|
||||
if (Cvar_VariableString(cmd_name)[0]) {
|
||||
Con_Printf("%s: %s already defined as a var\n", __func__, cmd_name);
|
||||
return;
|
||||
}
|
||||
// fail if the command already exists
|
||||
for (cmd = cmd_functions; cmd; cmd = cmd->next) {
|
||||
if (!strcmp(cmd_name, cmd->name)) {
|
||||
Con_Printf("%s: %s already defined\n", __func__, cmd_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cmd = Hunk_Alloc(sizeof(cmd_function_t));
|
||||
cmd->name = cmd_name;
|
||||
cmd->function = function;
|
||||
cmd->next = cmd_functions;
|
||||
cmd_functions = cmd;
|
||||
|
||||
insert_command_completion(cmd_name);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Exists
|
||||
============
|
||||
*/
|
||||
qboolean
|
||||
Cmd_Exists(char *cmd_name)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
|
||||
for (cmd = cmd_functions; cmd; cmd = cmd->next) {
|
||||
if (!strcmp(cmd_name, cmd->name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Cmd_ForwardToServer
|
||||
|
||||
Sends the entire command line over to the server
|
||||
===================
|
||||
*/
|
||||
void
|
||||
Cmd_ForwardToServer(void)
|
||||
{
|
||||
if (cls.state < ca_connected) {
|
||||
Con_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.demoplayback)
|
||||
return; // not really connected
|
||||
|
||||
MSG_WriteByte(&cls.message, clc_stringcmd);
|
||||
if (strcasecmp(Cmd_Argv(0), "cmd") != 0) {
|
||||
SZ_Print(&cls.message, Cmd_Argv(0));
|
||||
SZ_Print(&cls.message, " ");
|
||||
}
|
||||
if (Cmd_Argc() > 1)
|
||||
SZ_Print(&cls.message, Cmd_Args());
|
||||
else
|
||||
SZ_Print(&cls.message, "\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_ExecuteString
|
||||
|
||||
A complete command line has been parsed, so try to execute it
|
||||
FIXME: lookupnoadd the token to speed search?
|
||||
============
|
||||
*/
|
||||
void
|
||||
Cmd_ExecuteString(char *text, cmd_source_t src)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
cmdalias_t *a;
|
||||
|
||||
cmd_source = src;
|
||||
Cmd_TokenizeString(text);
|
||||
|
||||
// execute the command line
|
||||
if (!Cmd_Argc())
|
||||
return; // no tokens
|
||||
|
||||
// check functions
|
||||
for (cmd = cmd_functions; cmd; cmd = cmd->next) {
|
||||
if (!strcasecmp(cmd_argv[0], cmd->name)) {
|
||||
cmd->function();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check alias
|
||||
for (a = cmd_alias; a; a = a->next) {
|
||||
if (!strcasecmp(cmd_argv[0], a->name)) {
|
||||
Cbuf_InsertText(a->value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check cvars
|
||||
if (!Cvar_Command())
|
||||
Con_Printf("Unknown command \"%s\"\n", Cmd_Argv(0));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Cmd_CheckParm
|
||||
|
||||
Returns the position (1 to argc-1) in the command's argument list
|
||||
where the given parameter apears, or 0 if not present
|
||||
================
|
||||
*/
|
||||
int
|
||||
Cmd_CheckParm(char *parm)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!parm)
|
||||
Sys_Error("Cmd_CheckParm: NULL");
|
||||
|
||||
for (i = 1; i < Cmd_Argc(); i++)
|
||||
if (!strcasecmp(parm, Cmd_Argv(i)))
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
136
NQ/cmd.h
Normal file
136
NQ/cmd.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CMD_H
|
||||
#define CMD_H
|
||||
|
||||
#include "qtypes.h"
|
||||
|
||||
// cmd.h -- Command buffer and command execution
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
|
||||
Any number of commands can be added in a frame, from several different sources.
|
||||
Most commands come from either keybindings or console line input, but remote
|
||||
servers can also send across commands and entire text files can be execed.
|
||||
|
||||
The + command line options are also added to the command buffer.
|
||||
|
||||
The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute ();
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void Cbuf_Init(void);
|
||||
|
||||
// allocates an initial text buffer that will grow as needed
|
||||
|
||||
void Cbuf_AddText(char *text);
|
||||
|
||||
// as new commands are generated from the console or keybindings,
|
||||
// the text is added to the end of the command buffer.
|
||||
|
||||
void Cbuf_InsertText(char *text);
|
||||
|
||||
// when a command wants to issue other commands immediately, the text is
|
||||
// inserted at the beginning of the buffer, before any remaining unexecuted
|
||||
// commands.
|
||||
|
||||
void Cbuf_Execute(void);
|
||||
|
||||
// Pulls off \n terminated lines of text from the command buffer and sends
|
||||
// them through Cmd_ExecuteString. Stops when the buffer is empty.
|
||||
// Normally called once per frame, but may be explicitly invoked.
|
||||
// Do not call inside a command function!
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
|
||||
Command execution takes a null terminated string, breaks it into tokens,
|
||||
then searches for a command or variable that matches the first token.
|
||||
|
||||
// FIXME - this comment section and enum below not in QW (different behaviour)
|
||||
// - comment in QW explains it grep for QW_CMD_SOURCE
|
||||
Commands can come from three sources, but the handler functions may choose
|
||||
to dissallow the action or forward it to a remote server if the source is
|
||||
not apropriate.
|
||||
|
||||
*/
|
||||
|
||||
typedef void (*xcommand_t) (void);
|
||||
|
||||
typedef enum {
|
||||
src_client, // came in over a net connection as a clc_stringcmd
|
||||
// host_client will be valid during this state.
|
||||
src_command // from the command buffer
|
||||
} cmd_source_t;
|
||||
|
||||
extern cmd_source_t cmd_source;
|
||||
|
||||
void Cmd_Init(void);
|
||||
|
||||
void Cmd_AddCommand(char *cmd_name, xcommand_t function);
|
||||
|
||||
// called by the init functions of other parts of the program to
|
||||
// register commands and functions to call for them.
|
||||
// The cmd_name is referenced later, so it should not be in temp memory
|
||||
|
||||
qboolean Cmd_Exists(char *cmd_name);
|
||||
|
||||
// used by the cvar code to check for cvar / command name overlap
|
||||
|
||||
int Cmd_Argc(void);
|
||||
char *Cmd_Argv(int arg);
|
||||
char *Cmd_Args(void);
|
||||
|
||||
// The functions that execute commands get their parameters with these
|
||||
// functions. Cmd_Argv () will return an empty string, not a NULL
|
||||
// if arg > argc, so string operations are allways safe.
|
||||
|
||||
int Cmd_CheckParm(char *parm);
|
||||
|
||||
// Returns the position (1 to argc-1) in the command's argument list
|
||||
// where the given parameter apears, or 0 if not present
|
||||
|
||||
void Cmd_TokenizeString(char *text);
|
||||
|
||||
// Takes a null terminated string. Does not need to be /n terminated.
|
||||
// breaks the string up into arg tokens.
|
||||
|
||||
void Cmd_ExecuteString(char *text, cmd_source_t src);
|
||||
|
||||
// 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.
|
||||
|
||||
void Cmd_ForwardToServer(void);
|
||||
|
||||
// adds the current command line as a clc_stringcmd to the client message.
|
||||
// things like godmode, noclip, etc, are commands directed to the server,
|
||||
// so when they are typed in at the console, they will need to be forwarded.
|
||||
|
||||
void Cmd_Print(char *text);
|
||||
|
||||
// used by command functions to send output to either the graphics console or
|
||||
// passed as a print message to the client
|
||||
|
||||
#endif /* CMD_H */
|
1680
NQ/common.c
Normal file
1680
NQ/common.c
Normal file
File diff suppressed because it is too large
Load Diff
173
NQ/common.h
Normal file
173
NQ/common.h
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// common.h -- general definitions
|
||||
// FIXME - split this up better?
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "qtypes.h"
|
||||
|
||||
#define stringify__(x) #x
|
||||
#define stringify(x) stringify__(x)
|
||||
|
||||
//============================================================================
|
||||
|
||||
typedef struct sizebuf_s {
|
||||
qboolean allowoverflow; // if false, do a Sys_Error
|
||||
qboolean overflowed; // set to true if the buffer size failed
|
||||
byte *data;
|
||||
int maxsize;
|
||||
int cursize;
|
||||
} sizebuf_t;
|
||||
|
||||
void SZ_Alloc(sizebuf_t *buf, int startsize);
|
||||
void SZ_Free(sizebuf_t *buf);
|
||||
void SZ_Clear(sizebuf_t *buf);
|
||||
void *SZ_GetSpace(sizebuf_t *buf, int length);
|
||||
void SZ_Write(sizebuf_t *buf, void *data, int length);
|
||||
void SZ_Print(sizebuf_t *buf, char *data); // strcats onto the sizebuf
|
||||
|
||||
//============================================================================
|
||||
|
||||
typedef struct link_s {
|
||||
struct link_s *prev, *next;
|
||||
} link_t;
|
||||
|
||||
|
||||
void ClearLink(link_t *l);
|
||||
void RemoveLink(link_t *l);
|
||||
void InsertLinkBefore(link_t *l, link_t *before);
|
||||
void InsertLinkAfter(link_t *l, link_t *after);
|
||||
|
||||
// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
|
||||
// ent = STRUCT_FROM_LINK(link,entity_t,order)
|
||||
// FIXME: remove this mess!
|
||||
#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m)))
|
||||
|
||||
//============================================================================
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#define Q_MAXCHAR ((char)0x7f)
|
||||
#define Q_MAXSHORT ((short)0x7fff)
|
||||
#define Q_MAXINT ((int)0x7fffffff)
|
||||
#define Q_MAXLONG ((int)0x7fffffff)
|
||||
#define Q_MAXFLOAT ((int)0x7fffffff)
|
||||
|
||||
#define Q_MINCHAR ((char)0x80)
|
||||
#define Q_MINSHORT ((short)0x8000)
|
||||
#define Q_MININT ((int)0x80000000)
|
||||
#define Q_MINLONG ((int)0x80000000)
|
||||
#define Q_MINFLOAT ((int)0x7fffffff)
|
||||
|
||||
//============================================================================
|
||||
|
||||
extern qboolean bigendien;
|
||||
|
||||
extern short (*BigShort) (short l);
|
||||
extern short (*LittleShort) (short l);
|
||||
extern int (*BigLong) (int l);
|
||||
extern int (*LittleLong) (int l);
|
||||
extern float (*BigFloat) (float l);
|
||||
extern float (*LittleFloat) (float l);
|
||||
|
||||
//============================================================================
|
||||
|
||||
void MSG_WriteChar(sizebuf_t *sb, int c);
|
||||
void MSG_WriteByte(sizebuf_t *sb, int c);
|
||||
void MSG_WriteShort(sizebuf_t *sb, int c);
|
||||
void MSG_WriteLong(sizebuf_t *sb, int c);
|
||||
void MSG_WriteFloat(sizebuf_t *sb, float f);
|
||||
void MSG_WriteString(sizebuf_t *sb, char *s);
|
||||
void MSG_WriteCoord(sizebuf_t *sb, float f);
|
||||
void MSG_WriteAngle(sizebuf_t *sb, float f);
|
||||
|
||||
extern int msg_readcount;
|
||||
extern qboolean msg_badread; // set if a read goes beyond end of message
|
||||
|
||||
void MSG_BeginReading(void);
|
||||
int MSG_ReadChar(void);
|
||||
int MSG_ReadByte(void);
|
||||
int MSG_ReadShort(void);
|
||||
int MSG_ReadLong(void);
|
||||
float MSG_ReadFloat(void);
|
||||
char *MSG_ReadString(void);
|
||||
|
||||
float MSG_ReadCoord(void);
|
||||
float MSG_ReadAngle(void);
|
||||
|
||||
//============================================================================
|
||||
|
||||
int Q_atoi(const char *str);
|
||||
float Q_atof(const char *str);
|
||||
|
||||
//============================================================================
|
||||
|
||||
extern char com_token[1024];
|
||||
extern qboolean com_eof;
|
||||
|
||||
char *COM_Parse(char *data);
|
||||
|
||||
extern unsigned com_argc;
|
||||
extern char **com_argv;
|
||||
|
||||
unsigned COM_CheckParm(char *parm);
|
||||
void COM_Init(char *path);
|
||||
void COM_InitArgv(int argc, char **argv);
|
||||
|
||||
char *COM_SkipPath(char *pathname);
|
||||
void COM_StripExtension(char *in, char *out);
|
||||
void COM_FileBase(const char *in, char *out);
|
||||
void COM_DefaultExtension(char *path, char *extension);
|
||||
|
||||
char *va(char *format, ...);
|
||||
|
||||
// does a varargs printf into a temp buffer
|
||||
|
||||
//============================================================================
|
||||
|
||||
extern int com_filesize;
|
||||
struct cache_user_s;
|
||||
|
||||
extern char com_gamedir[MAX_OSPATH];
|
||||
|
||||
void COM_WriteFile(const char *filename, const void *data, int len);
|
||||
int COM_OpenFile(const char *filename, int *hndl);
|
||||
int COM_FOpenFile(const char *filename, FILE **file);
|
||||
void COM_CloseFile(int h);
|
||||
|
||||
byte *COM_LoadStackFile(const char *path, void *buffer, int bufsize,
|
||||
unsigned long *length);
|
||||
byte *COM_LoadTempFile(const char *path);
|
||||
byte *COM_LoadHunkFile(const char *path);
|
||||
void COM_LoadCacheFile(const char *path, struct cache_user_s *cu);
|
||||
|
||||
|
||||
extern struct cvar_s registered;
|
||||
|
||||
extern qboolean standard_quake, rogue, hipnotic;
|
||||
|
||||
#endif /* COMMON_H */
|
353
NQ/conproc.c
Normal file
353
NQ/conproc.c
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// conproc.c
|
||||
//
|
||||
// Stuff for the Win32 console (dedicated server only I guess)
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "conproc.h"
|
||||
#include "quakedef.h"
|
||||
|
||||
HANDLE heventDone;
|
||||
HANDLE hfileBuffer;
|
||||
HANDLE heventChildSend;
|
||||
HANDLE heventParentSend;
|
||||
HANDLE hStdout;
|
||||
HANDLE hStdin;
|
||||
|
||||
DWORD RequestProc(DWORD dwNichts);
|
||||
LPVOID GetMappedBuffer(HANDLE hfileBuffer);
|
||||
void ReleaseMappedBuffer(LPVOID pBuffer);
|
||||
BOOL GetScreenBufferLines(int *piLines);
|
||||
BOOL SetScreenBufferLines(int iLines);
|
||||
BOOL ReadText(LPTSTR pszText, int iBeginLine, int iEndLine);
|
||||
BOOL WriteText(LPCTSTR szText);
|
||||
int CharToCode(char c);
|
||||
BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy);
|
||||
|
||||
|
||||
void
|
||||
InitConProc(HANDLE hFile, HANDLE heventParent, HANDLE heventChild)
|
||||
{
|
||||
DWORD dwID;
|
||||
|
||||
// ignore if we don't have all the events.
|
||||
if (!hFile || !heventParent || !heventChild)
|
||||
return;
|
||||
|
||||
hfileBuffer = hFile;
|
||||
heventParentSend = heventParent;
|
||||
heventChildSend = heventChild;
|
||||
|
||||
// so we'll know when to go away.
|
||||
heventDone = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
if (!heventDone) {
|
||||
Con_SafePrintf("Couldn't create heventDone\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CreateThread(NULL,
|
||||
0, (LPTHREAD_START_ROUTINE) RequestProc, 0, 0, &dwID)) {
|
||||
CloseHandle(heventDone);
|
||||
Con_SafePrintf("Couldn't create QHOST thread\n");
|
||||
return;
|
||||
}
|
||||
// save off the input/output handles.
|
||||
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
// force 80 character width, at least 25 character height
|
||||
SetConsoleCXCY(hStdout, 80, 25);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DeinitConProc(void)
|
||||
{
|
||||
if (heventDone)
|
||||
SetEvent(heventDone);
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
RequestProc(DWORD dwNichts)
|
||||
{
|
||||
int *pBuffer;
|
||||
DWORD dwRet;
|
||||
HANDLE heventWait[2];
|
||||
int iBeginLine, iEndLine;
|
||||
|
||||
heventWait[0] = heventParentSend;
|
||||
heventWait[1] = heventDone;
|
||||
|
||||
while (1) {
|
||||
dwRet = WaitForMultipleObjects(2, heventWait, FALSE, INFINITE);
|
||||
|
||||
// heventDone fired, so we're exiting.
|
||||
if (dwRet == WAIT_OBJECT_0 + 1)
|
||||
break;
|
||||
|
||||
pBuffer = (int *)GetMappedBuffer(hfileBuffer);
|
||||
|
||||
// hfileBuffer is invalid. Just leave.
|
||||
if (!pBuffer) {
|
||||
Con_SafePrintf("Invalid hfileBuffer\n");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pBuffer[0]) {
|
||||
case CCOM_WRITE_TEXT:
|
||||
// Param1 : Text
|
||||
pBuffer[0] = WriteText((LPCTSTR)(pBuffer + 1));
|
||||
break;
|
||||
|
||||
case CCOM_GET_TEXT:
|
||||
// Param1 : Begin line
|
||||
// Param2 : End line
|
||||
iBeginLine = pBuffer[1];
|
||||
iEndLine = pBuffer[2];
|
||||
pBuffer[0] = ReadText((LPTSTR)(pBuffer + 1), iBeginLine,
|
||||
iEndLine);
|
||||
break;
|
||||
|
||||
case CCOM_GET_SCR_LINES:
|
||||
// No params
|
||||
pBuffer[0] = GetScreenBufferLines(&pBuffer[1]);
|
||||
break;
|
||||
|
||||
case CCOM_SET_SCR_LINES:
|
||||
// Param1 : Number of lines
|
||||
pBuffer[0] = SetScreenBufferLines(pBuffer[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
ReleaseMappedBuffer(pBuffer);
|
||||
SetEvent(heventChildSend);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LPVOID
|
||||
GetMappedBuffer(HANDLE hfileBuffer)
|
||||
{
|
||||
LPVOID pBuffer;
|
||||
|
||||
pBuffer = MapViewOfFile(hfileBuffer,
|
||||
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ReleaseMappedBuffer(LPVOID pBuffer)
|
||||
{
|
||||
UnmapViewOfFile(pBuffer);
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
GetScreenBufferLines(int *piLines)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
BOOL bRet;
|
||||
|
||||
bRet = GetConsoleScreenBufferInfo(hStdout, &info);
|
||||
|
||||
if (bRet)
|
||||
*piLines = info.dwSize.Y;
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
SetScreenBufferLines(int iLines)
|
||||
{
|
||||
|
||||
return SetConsoleCXCY(hStdout, 80, iLines);
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
ReadText(LPTSTR pszText, int iBeginLine, int iEndLine)
|
||||
{
|
||||
COORD coord;
|
||||
DWORD dwRead;
|
||||
BOOL bRet;
|
||||
|
||||
coord.X = 0;
|
||||
coord.Y = iBeginLine;
|
||||
|
||||
bRet = ReadConsoleOutputCharacter(hStdout,
|
||||
pszText,
|
||||
80 * (iEndLine - iBeginLine + 1),
|
||||
coord, &dwRead);
|
||||
|
||||
// Make sure it's null terminated.
|
||||
if (bRet)
|
||||
pszText[dwRead] = '\0';
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
WriteText(LPCTSTR szText)
|
||||
{
|
||||
DWORD dwWritten;
|
||||
INPUT_RECORD rec;
|
||||
char upper, *sz;
|
||||
|
||||
sz = (LPTSTR)szText;
|
||||
|
||||
while (*sz) {
|
||||
// 13 is the code for a carriage return (\n) instead of 10.
|
||||
if (*sz == 10)
|
||||
*sz = 13;
|
||||
|
||||
upper = toupper(*sz);
|
||||
|
||||
rec.EventType = KEY_EVENT;
|
||||
rec.Event.KeyEvent.bKeyDown = TRUE;
|
||||
rec.Event.KeyEvent.wRepeatCount = 1;
|
||||
rec.Event.KeyEvent.wVirtualKeyCode = upper;
|
||||
rec.Event.KeyEvent.wVirtualScanCode = CharToCode(*sz);
|
||||
rec.Event.KeyEvent.uChar.AsciiChar = *sz;
|
||||
rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
|
||||
rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0;
|
||||
|
||||
WriteConsoleInput(hStdin, &rec, 1, &dwWritten);
|
||||
|
||||
rec.Event.KeyEvent.bKeyDown = FALSE;
|
||||
|
||||
WriteConsoleInput(hStdin, &rec, 1, &dwWritten);
|
||||
|
||||
sz++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
CharToCode(char c)
|
||||
{
|
||||
char upper;
|
||||
|
||||
upper = toupper(c);
|
||||
|
||||
switch (c) {
|
||||
case 13:
|
||||
return 28;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isalpha(c))
|
||||
return (30 + upper - 65);
|
||||
|
||||
if (isdigit(c))
|
||||
return (1 + upper - 47);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
COORD coordMax;
|
||||
|
||||
coordMax = GetLargestConsoleWindowSize(hStdout);
|
||||
|
||||
if (cy > coordMax.Y)
|
||||
cy = coordMax.Y;
|
||||
|
||||
if (cx > coordMax.X)
|
||||
cx = coordMax.X;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(hStdout, &info))
|
||||
return FALSE;
|
||||
|
||||
// height
|
||||
info.srWindow.Left = 0;
|
||||
info.srWindow.Right = info.dwSize.X - 1;
|
||||
info.srWindow.Top = 0;
|
||||
info.srWindow.Bottom = cy - 1;
|
||||
|
||||
if (cy < info.dwSize.Y) {
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
|
||||
info.dwSize.Y = cy;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
} else if (cy > info.dwSize.Y) {
|
||||
info.dwSize.Y = cy;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(hStdout, &info))
|
||||
return FALSE;
|
||||
|
||||
// width
|
||||
info.srWindow.Left = 0;
|
||||
info.srWindow.Right = cx - 1;
|
||||
info.srWindow.Top = 0;
|
||||
info.srWindow.Bottom = info.dwSize.Y - 1;
|
||||
|
||||
if (cx < info.dwSize.X) {
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
|
||||
info.dwSize.X = cx;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
} else if (cx > info.dwSize.X) {
|
||||
info.dwSize.X = cx;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
44
NQ/conproc.h
Normal file
44
NQ/conproc.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONPROC_H
|
||||
#define CONPROC_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// conproc.h
|
||||
|
||||
#define CCOM_WRITE_TEXT 0x2
|
||||
// Param1 : Text
|
||||
|
||||
#define CCOM_GET_TEXT 0x3
|
||||
// Param1 : Begin line
|
||||
// Param2 : End line
|
||||
|
||||
#define CCOM_GET_SCR_LINES 0x4
|
||||
// No params
|
||||
|
||||
#define CCOM_SET_SCR_LINES 0x5
|
||||
// Param1 : Number of lines
|
||||
|
||||
void InitConProc(HANDLE hFile, HANDLE heventParent, HANDLE heventChild);
|
||||
void DeinitConProc(void);
|
||||
|
||||
#endif /* CONPROC_H */
|
1074
NQ/d_polyse.c
Normal file
1074
NQ/d_polyse.c
Normal file
File diff suppressed because it is too large
Load Diff
487
NQ/data/COMEXP.TXT
Normal file
487
NQ/data/COMEXP.TXT
Normal file
@ -0,0 +1,487 @@
|
||||
COMMERCIAL EXPLOITATION LICENSE AGREEMENT FOR QUAKE
|
||||
|
||||
This Commercial Exploitation License Agreement for QUAKE
|
||||
(the "Agreement") is between Id Software, Inc., a Texas
|
||||
Corporation, (hereinafter "Id Software") and Licensee (as described
|
||||
on the signature page hereof) and is made effective beginning on
|
||||
the date of last signature hereto (the "Effective Date").
|
||||
|
||||
R E C I T A L S
|
||||
|
||||
WHEREAS, Id Software is the owner and developer of the
|
||||
computer software game entitled QUAKE;
|
||||
|
||||
WHEREAS, Id Software desires to license certain
|
||||
non-exclusive rights regarding QUAKE to Licensee; and
|
||||
|
||||
WHEREAS, Licensee desires to receive a license for such
|
||||
rights.
|
||||
|
||||
T E R M S A N D C O N D I T I O N S
|
||||
|
||||
NOW, THEREFORE, for and in consideration of the mutual
|
||||
premises contained herein and for other good and valuable
|
||||
consideration, the receipt and sufficiency of which is hereby
|
||||
acknowledged, the undersigned parties do hereby agree as follows:
|
||||
|
||||
1. DEFINITIONS. As used in this Agreement, the parties
|
||||
hereto agree the words set forth below shall have the specified
|
||||
meanings:
|
||||
|
||||
a. "Authorized Copy" shall mean one (1) copy of the
|
||||
Subject Game actually purchased by Licensee from an
|
||||
Id Software approved retailer; and
|
||||
|
||||
b. "Subject Game" shall mean the full registered
|
||||
version of QUAKE on a CD-ROM and shall not mean the
|
||||
shareware or any other version.
|
||||
|
||||
2. GRANT OF RIGHTS. Id Software hereby grants to
|
||||
Licensee and Licensee hereby accepts, subject to the provisions and
|
||||
conditions hereof, a world-wide (except as otherwise provided
|
||||
herein), non-exclusive, non-transferable, and non-assignable
|
||||
license to:
|
||||
|
||||
a. publicly display an Authorized Copy in exchange for
|
||||
rental payment;
|
||||
|
||||
b. run the Authorized Copy so that it will accept
|
||||
network/modem connections in exchange for payments
|
||||
from end-users who also must have actually purchased
|
||||
an Authorized Copy; and
|
||||
|
||||
c. otherwise commercially exploit an Authorized Copy,
|
||||
except that Licensee shall not copy, reproduce,
|
||||
manufacture or distribute the Authorized Copy.
|
||||
|
||||
3. RESERVATION OF RIGHTS AND PROHIBITIONS. Id Software
|
||||
expressly reserves all rights not granted herein. Under no
|
||||
circumstances shall Licensee copy, reproduce, manufacture or
|
||||
distribute (free of charge or otherwise) the Authorized Copy or the
|
||||
Subject Game. Licensee shall not reverse engineer, decompile,
|
||||
disassemble, modify or alter the Authorized Copy. Licensee is not
|
||||
receiving any rights hereunder regarding the Trademark or any
|
||||
artwork, sound, music or other element of the Subject Game.
|
||||
|
||||
4. OWNERSHIP. Title to and all ownership rights in and
|
||||
to the Subject Game, and the QUAKE Trademark (the "Trademark") and
|
||||
the copyrights, trademarks, patents and other intellectual property
|
||||
rights related thereto shall remain with Id Software which shall have
|
||||
the exclusive right to protect the same by copyright or otherwise.
|
||||
Licensee shall have no ownership rights in or to the Subject Game or
|
||||
the Trademark and Licensee shall not own any intellectual property
|
||||
rights regarding the Authorized Copy, including, without limitation,
|
||||
the copyright regarding the Authorized Copy. Licensee acknowledges
|
||||
that it only has a limited license to use the Authorized Copy, as
|
||||
specified in that certain QUAKE Enduser License contained within the
|
||||
Authorized Copy and as specified in this Agreement.
|
||||
|
||||
5. TERM AND TERMINATION.
|
||||
|
||||
a. The term of this Agreement and the license granted
|
||||
herein begins on the Effective Date and shall expire on a date one
|
||||
(1) calendar year from the Effective Date.
|
||||
|
||||
b. Either party may terminate this Agreement, for any
|
||||
reason or no reason, on thirty (30) days written notice to the
|
||||
other party. Termination will be effective on the thirtieth (30th)
|
||||
day following delivery of the described notice. Notwithstanding
|
||||
anything to the contrary herein, this Agreement shall immediately
|
||||
terminate, without the requirement of any notice from Id Software
|
||||
to Licensee, upon the occurrence of any of the following: (a) if
|
||||
Licensee shall file a petition in bankruptcy or make an assignment
|
||||
for the benefit of creditors, or if any bankruptcy proceeding or
|
||||
assignment for benefit of creditors, shall be commenced against
|
||||
Licensee and not be dismissed within sixty (60) days after the date
|
||||
of its commencement; (b) the insolvency of Licensee; (c) the
|
||||
cessation by Licensee of its business; or (d) the cessation by
|
||||
Licensee, without the prior written consent of Id Software of the
|
||||
distribution, manufacture, and sale responsibilities embodied
|
||||
herein. Further, Id Software may elect to terminate this Agreement
|
||||
upon the occurrence of any of the following: (1) if Licensee's
|
||||
business operations are interrupted for forty (40) consecutive
|
||||
calendar days; or (2) if each of two Id Software audit inspections
|
||||
during any eighteen (18) month period demonstrates an
|
||||
understatement by Licensee of Royalty payments due Id Software for
|
||||
the six (6) month period immediately preceding each such inspection
|
||||
of five percent (5%) or more. Upon the occurrence of such
|
||||
terminating event, and the election of Id Software, if necessary,
|
||||
to cause such termination, this Agreement and any and all rights
|
||||
thereunder shall terminate without prejudice to any rights or
|
||||
claims Id Software may have, and all rights hereunder shall
|
||||
thereupon terminate, revert to and be vested in Id Software.
|
||||
|
||||
6. EFFECT OF TERMINATION OR EXPIRATION. Termination or
|
||||
expiration of this Agreement, either by Id Software or
|
||||
automatically, shall not create any liability against Id Software.
|
||||
Upon expiration or earlier termination of this Agreement, Licensee
|
||||
shall have no further right to exercise the rights licensed
|
||||
hereunder or otherwise acquired in relation to this Agreement.
|
||||
|
||||
7. INDEMNIFICATION. Licensee hereby agrees to
|
||||
indemnify, hold harmless and defend Id Software and Id Software's
|
||||
predecessors, successors, assigns, officers, directors,
|
||||
shareholders, employees, agents, representatives, licensees,
|
||||
sublicensees, distributors, attorneys and accountants
|
||||
(collectively, the "Id Related Parties") from and against any and
|
||||
all damages, claims, losses, causes of action, liabilities,
|
||||
lawsuits, judgments and expenses (including, without limitation,
|
||||
reasonable attorneys' fees and expenses) arising from, relating to
|
||||
or in connection with a breach of this Agreement by Licensee and
|
||||
arising from, relating to or in connection with the Licensee's use
|
||||
or non-use of the Authorized Copy (collectively, the "Claims"). Id
|
||||
Software agrees to notify Licensee of any such Claims within a
|
||||
reasonable time after Id Software learns of same. Licensee, at its
|
||||
own expense, shall defend Id Software and the Id Related Parties
|
||||
from any and all Claims. Id Software and the Id Related Parties
|
||||
reserve the right to participate in any defense of the Claims with
|
||||
counsel of their choice, and at their own expense. In the event
|
||||
Licensee fails to provide a defense, then Licensee shall be
|
||||
responsible for paying the attorneys' fees and expenses incurred by
|
||||
Id Software and the Id Related Parties regarding the defense of the
|
||||
Claims. Id Software and the Id Related Parties, as applicable,
|
||||
agree to reasonably assist in the defense of the Claims. No
|
||||
settlement by Licensee of any Claims shall be valid unless Licensee
|
||||
receives the prior written consent of Id Software and the Id
|
||||
Related Parties, as applicable, to any such settlement.
|
||||
|
||||
8. CONFIDENTIALITY. It is understood and agreed that
|
||||
any proprietary information of Id Software that may from time to
|
||||
time be made available or become known to Licensee is to be treated
|
||||
as confidential, is to be used solely in connection with Licensee's
|
||||
performance under this Agreement, and is to be disclosed only to
|
||||
employees of Licensee who have a need for access. Such proprietary
|
||||
information shall include, but not be limited to, trade secrets,
|
||||
release information, financial information, personnel information,
|
||||
and the like. Reasonable measures shall be taken by Licensee to
|
||||
protect the confidentiality of Id Software's proprietary
|
||||
information and any memoranda or papers containing proprietary
|
||||
information of Id Software's that Licensee may receive are to be
|
||||
returned to Id Software upon request. Licensee's obligations and
|
||||
duties under this paragraph shall survive expiration or earlier
|
||||
termination of this Agreement. Licensee shall obtain from its
|
||||
employees an undertaking in a form which may be supplied by Id
|
||||
Software, and which is subject to Id Software's prior written
|
||||
approval, not to use or disclose to any third party any information
|
||||
or knowledge concerning the business of Id Software which may be
|
||||
communicated to such employees.
|
||||
|
||||
9. LIMITATION OF LIABILITY. ID SOFTWARE EXPRESSLY
|
||||
DISCLAIMS ALL WARRANTIES NOT PROVIDED BY ID SOFTWARE HEREUNDER.
|
||||
UNDER NO CIRCUMSTANCES SHALL ID SOFTWARE BE LIABLE TO LICENSEE FOR
|
||||
ACTUAL, SPECIAL, INCIDENTAL, CONSEQUENTIAL OR PUNITIVE DAMAGES OR
|
||||
ANY OTHER DAMAGES, WHETHER OR NOT ID SOFTWARE RECEIVES NOTICE OF
|
||||
ANY SUCH DAMAGES.
|
||||
|
||||
10. COMPLIANCE WITH APPLICABLE LAWS. In performing
|
||||
under this Agreement, Licensee agrees to comply with all applicable
|
||||
laws, [including, without limitation, 22 U.S.C., 2778 and 22
|
||||
U.S.C. C.F.R. Parts 120-130 (1995)] regulations, ordinances and
|
||||
statutes, including, but not limited to, the import/export laws and
|
||||
regulations of the United States and its governmental and
|
||||
regulatory agencies (including, without limitation, the Bureau of
|
||||
Export Administration and the U.S. Department of Commerce) and all
|
||||
applicable international treaties and laws. Further, Licensee
|
||||
shall defend, indemnify and hold harmless Id Software from any and
|
||||
all sales tax, tariffs and/or duties in connection with Licensee's
|
||||
performance hereunder.
|
||||
|
||||
11. SPECIFIC UNDERTAKINGS BY LICENSEE. In addition to
|
||||
the obligations of Licensee otherwise set forth in this Agreement,
|
||||
during the term of this Agreement, and thereafter where specified,
|
||||
Licensee agrees that:
|
||||
|
||||
a. It will not attack the title of Id Software to the
|
||||
Subject Game or the Trademark and any copyright, patent or
|
||||
trademark or other intellectual property right related thereto and
|
||||
it will not attack the validity of the license granted hereunder
|
||||
during the term hereof or thereafter; and
|
||||
|
||||
b. It will promptly inform Id Software of any
|
||||
unauthorized use of the Authorized Copy, the Subject Game and the
|
||||
Trademark and any portions thereof and reasonably assist Id
|
||||
Software in the enforcement of any rights Id Software may have
|
||||
against such unauthorized users.
|
||||
|
||||
12. FINANCIAL OBLIGATIONS AND ACCOUNTING.
|
||||
|
||||
a. Payment of Royalties. Licensee agrees to pay Id
|
||||
Software a royalty ("Royalty") at the rate of twelve and one-half
|
||||
percent (12.5%) of Net Income. The term "Net Income" shall mean
|
||||
all revenue received by Licensee from the commercial use of the
|
||||
Authorized Copy, less only Licensee's actual, documented costs
|
||||
relating directly to such use. A Royalty shall only be due for
|
||||
those months in which Licensee's gross revenue from QUAKE
|
||||
distribution exceeds U.S. Five Thousand Dollars ($5,000.00) and in
|
||||
such months Licensee shall pay a full Royalty on all revenue
|
||||
received.
|
||||
|
||||
b. Rendition of Statements. Licensee shall account to
|
||||
Id Software with regard to transactions hereunder within forty-five
|
||||
(45) days following the conclusion of each calendar quarter.
|
||||
Licensee hereby represents and warrants that such statements of
|
||||
account to be prepared shall be true and correct. The accounts
|
||||
shall show in summary form the appropriate calculations relating to
|
||||
the computation of Royalties, if any. The statements shall also
|
||||
show the gross revenue received by Licensee per month. The
|
||||
Royalties payable to Id Software hereunder shall be remitted with
|
||||
the particular statement indicating such amount to be due. All
|
||||
statements hereunder shall be deemed rendered when deposited,
|
||||
postage prepaid, in the United States mail, addressed to Id
|
||||
Software at Id Software's address set forth on the signature page
|
||||
hereof.
|
||||
|
||||
c. Books of Account and Audits. Licensee shall keep
|
||||
books of account relating to the commercial use of the Authorized
|
||||
Copy on the basis of generally accepted accounting principles and
|
||||
shall maintain such books of account for a period of at least two
|
||||
(2) years after the expiration or earlier termination of this
|
||||
Agreement; provided, however, that Licensee shall not be required
|
||||
to keep such records longer than seven (7) years from their date of
|
||||
origination. Id Software may, upon reasonable notice and at its
|
||||
own expense, audit the applicable records at Licensee's office, in
|
||||
order to verify statements rendered hereunder. Any such audit
|
||||
shall take place during reasonable business hours and in such
|
||||
manner so as not to interfere with Licensee's normal business
|
||||
activities. Id Software agrees that such information inspected
|
||||
and/or copied on behalf of Id Software hereunder shall be used only
|
||||
for the purpose of determining the accuracy of the statements, and
|
||||
shall be revealed only to such officers, directors, employees,
|
||||
agents and/or representatives of Id Software as necessary to verify
|
||||
the accuracy of the statements. If in an audit of Licensee's books
|
||||
and records it is determined that there is a short fall of ten
|
||||
percent (10%) or more in Royalties reported for any calendar
|
||||
quarter, in addition to payment of such short fall and interest as
|
||||
may be due, as provided herein, Licensee shall reimburse Id
|
||||
Software for the full out-of-pocket costs of the audit including
|
||||
reasonable travel costs and expenses; provided, however, that the
|
||||
amount of reimbursement paid by Licensee shall not exceed U.S.
|
||||
Fifteen Thousand Dollars ($15,000.00) for any audit.
|
||||
|
||||
d. Payment of the Royalty. Licensee assumes all risks
|
||||
associated with fluctuations in foreign currency exchange rates.
|
||||
Licensee shall pay and agrees to pay all sums due Id Software in
|
||||
United States Dollars. With respect to Royalties due for
|
||||
commercial use outside the United States, other currencies shall be
|
||||
exchanged at the expense of Licensee into United States Dollars
|
||||
using the bid price quoted at the Citibank, N.A. of New York, New
|
||||
York, for the purchase of United States Dollars at the close of
|
||||
business on the last day of the calendar quarter during which any
|
||||
amounts accrue. Payment of the Royalties shall be made in Dallas
|
||||
County, Texas.
|
||||
|
||||
e. Interest. If Id Software does not receive the
|
||||
applicable Royalty payment on or before the due date of such
|
||||
payment, Licensee agrees to pay and shall pay interest on Royalties
|
||||
owed to Id Software from such date as specified in the following
|
||||
sentence at a rate per annum equal to the Index Rate. For purposes
|
||||
of clarification, the interest will begin to accrue on the first
|
||||
(1st) day following the due date of the Royalty payment, unless the
|
||||
Royalty payment is paid timely. The "Index Rate" shall be the
|
||||
prime rate as published in The Wall Street Journal's "Money Rates"
|
||||
table. If multiple prime rates are quoted in the table, then the
|
||||
highest prime rate will be the Index Rate. In the event that the
|
||||
prime rate is no longer published in the "Money Rates" table, then
|
||||
Id Software will choose a substitute Index Rate which is based upon
|
||||
comparable information. The applicable interest rate will be
|
||||
determined and take effect on the first day of each month.
|
||||
|
||||
NOTHING HEREIN SHALL BE CONSTRUED AS A REQUEST OR DEMAND BY
|
||||
ID SOFTWARE OF INTEREST AT A RATE HIGHER THAN ALLOWED BY APPLICABLE
|
||||
LAW. IT IS THE INTENT OF THE PARTIES HERETO THAT NO INTEREST BE
|
||||
CHARGED HEREUNDER WHICH EXCEEDS THE MAXIMUM RATE ALLOWED BY
|
||||
APPLICABLE LAW. IF THE RATE REFERENCED ABOVE EXCEEDS THE MAXIMUM
|
||||
RATE ALLOWED BY APPLICABLE LAW, THEN THE INTEREST RATE MADE
|
||||
APPLICABLE HEREIN SHALL BE THE MAXIMUM RATE ALLOWED BY APPLICABLE
|
||||
LAW.
|
||||
|
||||
13. SUBLICENSE. Licensee shall not be entitled to
|
||||
sublicense any of its rights under this Agreement.
|
||||
|
||||
14. GOODWILL. Licensee recognizes the great value of
|
||||
the goodwill associated with the Subject Game and the Trademark,
|
||||
and acknowledges that such goodwill, now existing and hereafter
|
||||
created, exclusively belongs to Id Software and that the Trademark
|
||||
has acquired a secondary meaning in the mind of the public.
|
||||
|
||||
15. REMEDIES. In the event of a breach of this
|
||||
Agreement by Id Software, Licensee's sole remedy shall be to
|
||||
terminate this Agreement. In the event of a breach by Licensee of
|
||||
this Agreement, Id Software may pursue the remedies to which it is
|
||||
entitled under applicable law, including, but not limited to,
|
||||
termination of this Agreement. Licensee agrees that its failure to
|
||||
comply with the terms of this Agreement upon expiration or earlier
|
||||
termination hereof or Licensee's unauthorized use of the Authorized
|
||||
Copy may result in immediate and irreparable damage to Id Software
|
||||
for which there is no adequate remedy at law, and in the event of
|
||||
such failure by Licensee, Id Software shall be entitled to
|
||||
injunctive relief. Pursuit of any remedy by Id Software shall not
|
||||
constitute a waiver of any other right or remedy of Id Software
|
||||
under this Agreement or under applicable law. Termination of this
|
||||
Agreement shall not be a pre-condition to Id Software pursuing its
|
||||
other remedies for breach.
|
||||
|
||||
16. LICENSEE'S WARRANTIES. Licensee warrants and
|
||||
represents that it has full legal rights to enter into this
|
||||
Agreement and to perform its obligations hereunder and that it will
|
||||
comply, at all times during the terms of this Agreement, with all
|
||||
applicable laws, as set forth hereinabove.
|
||||
|
||||
17. BANKRUPTCY. If Licensee's liabilities exceed its
|
||||
assets, or if Licensee becomes unable to pay its debts as they
|
||||
become due or if Licensee files for voluntary bankruptcy, or is
|
||||
placed in bankruptcy which is not dissolved or dismissed after
|
||||
thirty (30) days from the petition filing date, or if Licensee
|
||||
becomes insolvent, or makes an assignment for the benefit of its
|
||||
creditors or an arrangement pursuant to any bankruptcy laws or if
|
||||
Licensee discontinues its business or if a receiver is appointed
|
||||
for its business, this Agreement shall automatically terminate,
|
||||
without notice, and become null and void; provided, however, all
|
||||
duties of Licensee upon termination or expiration of this Agreement
|
||||
shall continue in full force and effect.
|
||||
|
||||
18. ENTIRE AGREEMENT AND ASSIGNMENT. This Agreement
|
||||
constitutes the entire understanding between Licensee and Id
|
||||
Software regarding the Subject Game. Each and every clause of this
|
||||
Agreement is severable from the whole and shall survive unless the
|
||||
entire Agreement is declared unenforceable. No prior or present
|
||||
agreements or representations shall be binding upon any of the
|
||||
parties hereto unless incorporated in this Agreement. No
|
||||
modification or change in this Agreement shall be valid or binding
|
||||
upon the parties unless in writing, executed by the parties to be
|
||||
bound thereby. This Agreement shall bind and inure to the benefit
|
||||
of Id Software, its successors and assigns, and Id Software may
|
||||
assign its rights hereunder, in Id Software's sole discretion.
|
||||
This Agreement is personal to Licensee, and Licensee shall not
|
||||
sublicense, assign, transfer, convey nor franchise its rights
|
||||
granted hereunder.
|
||||
|
||||
19. CHOICE OF LAW, VENUE AND SERVICE OF PROCESS. This
|
||||
Agreement shall be construed in accordance with the laws of the
|
||||
State of Texas and applicable U.S. federal law and all claims
|
||||
and/or lawsuits in connection with this Agreement must be brought
|
||||
in Dallas County, Texas. Licensee hereby agrees that service of
|
||||
process by certified mail to the address set forth below, with
|
||||
return receipt requested, shall constitute valid service of process
|
||||
upon Licensee. If for any reason Licensee has moved or cannot be
|
||||
validly served, then Licensee appoints the Secretary of State of
|
||||
the state of Texas to accept service of process on Licensee's
|
||||
behalf.
|
||||
|
||||
20. EXCUSED PERFORMANCE. Neither party shall be deemed
|
||||
to be in default of any provision of this Agreement nor be liable
|
||||
for any delay, failure in performance or interruption of service,
|
||||
resulting directly or indirectly from acts of God, civil or
|
||||
military authority, civil disturbance, military action, war,
|
||||
strikes, other catastrophes or any other similar cause beyond its
|
||||
reasonable control. Written notice to the non-affected party of any
|
||||
such condition shall be given by the affected party within ten (10)
|
||||
days of the event.
|
||||
|
||||
21. DELIVERY OF NOTICES, AND DELIVERY OF PAYMENTS.
|
||||
Unless otherwise directed in writing by the parties, all notices
|
||||
given hereunder and all payments made hereunder shall be sent to
|
||||
the addresses set forth on the signature page hereof. All
|
||||
notices, requests, consents and other communications under this
|
||||
Agreement shall be in writing and shall be deemed to have been
|
||||
delivered on the date personally delivered or on the date deposited
|
||||
in the United States Postal Service, postage prepaid, by certified
|
||||
mail, return receipt requested, or telegraphed and confirmed, or
|
||||
delivered by electronic facsimile and confirmed. Any notice to Id
|
||||
Software shall also be sent to its counsel: D. Wade Cloud, Jr.,
|
||||
Hiersche, Martens, Hayward, Drakeley & Urbach, P.C., 15303 Dallas
|
||||
Parkway, Suite 700, LB 17, Dallas, Texas 75248.
|
||||
|
||||
22. NO PARTNERSHIP, ETC. This Agreement does not
|
||||
constitute and shall not be construed as constituting a partnership
|
||||
or joint venture between Id Software and Licensee. Neither party
|
||||
shall have any right to obligate or bind the other party in any
|
||||
manner whatsoever, and nothing herein contained shall give, or is
|
||||
intended to give, any rights of any kind to any third persons.
|
||||
|
||||
23. COUNTERPARTS. This Agreement may be executed in
|
||||
several counterparts, each of which will be deemed to be an
|
||||
original, and each of which alone and all of which together, shall
|
||||
constitute one and the same instrument, but in making proof of this
|
||||
Agreement it shall not be necessary to produce or account for each
|
||||
copy of any counterpart other than the counterpart signed by the
|
||||
party against whom this Agreement is to be enforced. This
|
||||
Agreement may be transmitted by facsimile, and it is the intent of
|
||||
the parties for the facsimile of any autograph printed by a
|
||||
receiving facsimile machine to be an original signature and for the
|
||||
facsimile and any complete photocopy of the Agreement to be deemed
|
||||
an original counterpart.
|
||||
|
||||
24. MEDIATION. If a dispute arises out of or relates to
|
||||
this Agreement, or a breach of this Agreement, and if the dispute
|
||||
cannot be settled through direct discussion, then the parties agree
|
||||
to endeavor to settle the dispute in an amicable manner by
|
||||
mediation, under the applicable provisions of Section 154.00 et
|
||||
seq., Texas Civil Practices and Remedies Code, as supplemented by
|
||||
the rules of the Association of Attorney Mediators.
|
||||
|
||||
25. SURVIVAL. The following provisions shall survive
|
||||
the expiration or earlier termination of this Agreement:
|
||||
paragraphs 4., 7., 8., and the audit rights of Id Software in
|
||||
paragraph 12.c.
|
||||
|
||||
26. MISCELLANEOUS.
|
||||
|
||||
a. All captions in this Agreement are intended solely
|
||||
for the convenience of the parties, and none shall effect the
|
||||
meaning or construction of any provision.
|
||||
|
||||
b. The terms and conditions of this Agreement have been
|
||||
negotiated fully and freely among the parties. Accordingly, the
|
||||
preparation of this Agreement by counsel for a given party will not
|
||||
be material to the construction hereof, and the terms of this
|
||||
Agreement shall not be strictly construed against such party.
|
||||
|
||||
By signing in the spaces provided below, the parties have
|
||||
agreed to all of the terms and conditions set forth in this
|
||||
Agreement.
|
||||
|
||||
|
||||
AGREED:
|
||||
|
||||
LICENSEE:
|
||||
|
||||
|
||||
Signed:_______________________________
|
||||
Printed Name:_________________________
|
||||
Title:________________________________
|
||||
Address:______________________________
|
||||
______________________________________
|
||||
______________________________________
|
||||
Telephone #: _________________________
|
||||
Fax #:________________________________
|
||||
E-Mail Address:_______________________
|
||||
Date: ________________________________
|
||||
|
||||
|
||||
AGREED:
|
||||
|
||||
ID SOFTWARE, INC.
|
||||
|
||||
|
||||
Signed:_______________________________
|
||||
Printed Name:_________________________
|
||||
Title:________________________________
|
||||
Address:______________________________
|
||||
______________________________________
|
||||
______________________________________
|
||||
Telephone #: _________________________
|
||||
Fax #:________________________________
|
||||
E-Mail Address:_______________________
|
||||
Date: ________________________________
|
||||
|
||||
|
||||
|
||||
June 10, 1996
|
||||
|
||||
|
||||
|
||||
COMMERCIAL EXPLOITATION LICENSE AGREEMENT FOR QUAKE
|
||||
(DWC:dw:3406.0299:dwc\doc:5017)
|
||||
|
||||
|
119
NQ/data/HELP.TXT
Normal file
119
NQ/data/HELP.TXT
Normal file
@ -0,0 +1,119 @@
|
||||
TECH SUPPORT
|
||||
Any of the information listed below could change. Check the id software
|
||||
Web Site, at www.idsoftware.com, for updates.
|
||||
|
||||
A. Tech Support Options
|
||||
id Software does charge for technical support, but we strive to offer
|
||||
this service at the lowest cost possible. Because volume on the support
|
||||
lines dictate costs, we periodically adjust our rates for Voice Tech
|
||||
Support. Check our web site for current pricing.
|
||||
|
||||
Paying for Voice or Automated Support
|
||||
1 -- You can get Voice Support using a major credit card for a one-time
|
||||
shot. The system asks for your credit card number and expiration date,
|
||||
then pre-authorizes your credit card for the tech support call. You will
|
||||
only be billed for the number of minutes actually used.
|
||||
|
||||
2 -- You can assign yourself a rechargeable PIN account. The system prompts
|
||||
you for your credit card information, and assigns you a PIN account number.
|
||||
You can use the PIN to access Voice Support, Automated Support and the
|
||||
Game Hints Line. Once your account runs out, you can charge it up again.
|
||||
|
||||
3 -- You may also charge up a PIN account using the number 1 (900) call-2-id.
|
||||
Then call back at 1(800)ID-GAMES (1(800)434-3627), and use your new PIN to
|
||||
receive all the support and hints you wish.
|
||||
|
||||
4 -- id Software's Game Hints Line is accessible either using a PIN account
|
||||
via 1 (800) ID-GAMES (see above), or by calling 1 (900) CALL2-ID, which
|
||||
places the call on your phone bill.
|
||||
|
||||
1. Voice Support
|
||||
Telephone -- 1 (800) id-games
|
||||
|
||||
Lines Open from 12 noon to 10pm Central Time, 7 Days a
|
||||
week ($1.75 per minute). Closed some holidays
|
||||
|
||||
Please have the following information handy.
|
||||
1. Game title and version number. (The version
|
||||
number can be found on the end text screen.)
|
||||
2. Your operating system, processor, processor
|
||||
speed and amount of RAM.
|
||||
3. If you are having a sound, video or modem
|
||||
problem, we need to know the device brand name
|
||||
and model.
|
||||
|
||||
2. Automated Support
|
||||
Telephone -- 1 (800) id-games
|
||||
|
||||
Lines Open 24 hours a day, 365 days a year, or 366 days
|
||||
in Leap years ($0.25 per minute)
|
||||
|
||||
Please have pencil and paper handy.
|
||||
|
||||
3. E-mail Support
|
||||
Just send your e-mail to support@idsoftware.com
|
||||
|
||||
We will do our best to respond within 48 hours after
|
||||
receiving your e-mail.
|
||||
|
||||
When sending e-mail, cut and paste the following into your
|
||||
e-mail message and fill in the blanks:
|
||||
|
||||
Date:
|
||||
Name:
|
||||
Phone number:
|
||||
E-mail address: (please include this, we redirect tons of mail)
|
||||
Game Title:
|
||||
Version #:
|
||||
Operating system (eg., DOS 6.0 or Windows 95):
|
||||
Computer type:
|
||||
Processor type:
|
||||
Processor speed:
|
||||
Video card brand and model: (only if video problem)
|
||||
Audio card brand and model: (only if audio problem)
|
||||
Modem brand and model: (only if modem problem)
|
||||
Network card brand and model: (only if netgame problem)
|
||||
Network configuration (eg., NET.CFG file): (only if netgame problem)
|
||||
Drivers, protocol stacks, and versions: (eg., lsl v2.14, exp16odi
|
||||
v2.33, and ipxodi v3.01) (only if netgame problem)
|
||||
If there were any error messages or fault information, report them
|
||||
here:
|
||||
Please state the problem you encountered:
|
||||
Please state how to reproduce the problem:
|
||||
|
||||
4. Web Support
|
||||
Found at www.idsoftware.com
|
||||
|
||||
Our web support pages provide the same information that's
|
||||
available via Automated Support, except it's free!
|
||||
|
||||
5. News Sites
|
||||
For information, FAQ, or announcements:
|
||||
rec.games.computer.quake.announce
|
||||
For editing and hecking Quake-related files:
|
||||
rec.games.computer.quake.editing
|
||||
For general Quake discussion:
|
||||
rec.games.computer.quake.misc
|
||||
|
||||
6. Game Hints Line
|
||||
Telephone -- 1 (800) id-games or 1 (900) call-2-id
|
||||
|
||||
Lines Open 24 hours a day, 365 days a year, or 366 days
|
||||
in Leap years ($0.85 per minute)
|
||||
You must be 18 years of age or have parental permission
|
||||
to call 1 (900) call-2-id.
|
||||
|
||||
B. In Europe
|
||||
The help lines in Europe are open 7:30am - 5:00pm GMT,
|
||||
Monday - Friday.
|
||||
|
||||
English: +44 01923 209145
|
||||
German: +44 (0)1923 209151
|
||||
French: +44 (0)1923 209148
|
||||
|
||||
C. Problems
|
||||
If you have an unfavorable experience using our services, please
|
||||
send e-mail to 911@idsoftware.com. We would also like to hear
|
||||
from you if you have something positive to share with us. Kindly
|
||||
include your full name, address, phone number, and the problem
|
||||
encountered or information you'd like to tell us about.
|
97
NQ/data/LICINFO.TXT
Normal file
97
NQ/data/LICINFO.TXT
Normal file
@ -0,0 +1,97 @@
|
||||
Here is a brief explanation of all the legal mumbo jumbo contained in the
|
||||
various license agreements that may or may not be part of this package.
|
||||
|
||||
(This document was designed to be a quick overview of our license terms.
|
||||
You must refer to the full text of the license for a complete listing of
|
||||
terms and conditions.)
|
||||
|
||||
QUAKE SHAREWARE END USER LICENSE (slicnse.txt) or
|
||||
What You Can and Cannot Do With the Shareware Version of Quake.
|
||||
|
||||
CAN DO:
|
||||
-- Play & Enjoy the single player game
|
||||
-- Setup a shareware version based server on a not-for-profit basis
|
||||
|
||||
CANNOT DO:
|
||||
-- Run the game with user developed levels.
|
||||
-- You may not commercially exploit the shareware version in any way
|
||||
This specifically excludes retail distribution of the shareware
|
||||
version. Do not call or e-mail to ask if you can be a retail
|
||||
distributor of the shareware version -- the answer is no!
|
||||
-- Commercially exploit any id copyrighted and/or trademarked property.
|
||||
Example: Game names, logos, graphics, etc.
|
||||
|
||||
|
||||
QUAKE REGISTERED VERSION END USER LICENSE (rlicnse.txt) or
|
||||
What You Can and Cannot Do With the Registered Version of Quake.
|
||||
|
||||
CAN DO:
|
||||
-- Play & Enjoy the single player game
|
||||
-- Setup a registered version based server on a not-for-profit basis
|
||||
-- Develop new levels and/or level creation utilities.
|
||||
-- Play the game and/or setup a Registered Version based server using
|
||||
a user-developed level.
|
||||
|
||||
CANNOT DO:
|
||||
-- Commercially exploit the Registered Version of Quake in any way;
|
||||
see commercially exploitation license info below.
|
||||
-- Commercially exploit any id copyrighted and/or trademarked
|
||||
property.
|
||||
Example: Game names, logos, game graphics, etc.
|
||||
-- Sell user-developed levels and/or tools
|
||||
|
||||
COMMERCIAL EXPLOITATION LICENSE (comexp.txt -- accompanies Quake
|
||||
registered version only)
|
||||
|
||||
If you are interested in trying to make money using the registered version
|
||||
of Quake (this sort of thing is not allowed using the shareware version) you
|
||||
must sign our easy-to-digest Commercial Exploitation License.
|
||||
|
||||
This is a royalty free license that allows you to run Quake for a profit
|
||||
through a certain monthly gross profit range. If your Quake-related business
|
||||
becomes successful the agreement brings id into the revenue stream.
|
||||
|
||||
Basic terms of the commercial exploitation license:
|
||||
|
||||
-- License grants a royalty free commercial exploitation right for the
|
||||
registered version of Quake as a whole so long as Quake's monthly gross
|
||||
revenue is below $5,000.00
|
||||
|
||||
-- License provides for a 12.5% royalty to be paid to id Software in months
|
||||
where the licensee's Quake related monthly gross revenue is above $5,000.00
|
||||
|
||||
-- Royalty is based off net income. Net income is defined as Quake-related
|
||||
gross income less Quake-related expenses.
|
||||
|
||||
-- License expressly prohibits commercial exploitation via the sale (retail
|
||||
or otherwise) of the shareware or registered versions of Quake.
|
||||
|
||||
-- License expressly prohibits advertising/marketing use of our copyrighted
|
||||
and/or trademarked properties.
|
||||
|
||||
To get into bed with us on this deal you must print two (2) copies of the
|
||||
document named comexp.txt. (You should find comexp.txt somewhere on the
|
||||
registered version CD.) Sign/fill in the blanks of both copies where
|
||||
indicated and mail both to:
|
||||
|
||||
id Software
|
||||
18601 LBJ #666
|
||||
Mesquite, TX 75150
|
||||
Attn: ComExp License
|
||||
|
||||
We will then countersign the documents and mail one back to you.
|
||||
|
||||
Two items worth noting here:
|
||||
|
||||
1. It is VERY IMPORTANT that the information you enter in the signature
|
||||
block be legible. We prefer it if you enter the info into the blanks before
|
||||
printing your two copies. If we cannot read your information we will not be
|
||||
able to return the documents to you.
|
||||
|
||||
2. The terms of this document are not subject to negotiation. If you cannot
|
||||
live with the terms spelled out in the agreement do not engage in any
|
||||
commercial exploitation of Quake and do not sign the document.
|
||||
|
||||
|
||||
|
||||
|
1030
NQ/data/MANUAL.TXT
Normal file
1030
NQ/data/MANUAL.TXT
Normal file
File diff suppressed because it is too large
Load Diff
103
NQ/data/ORDER.TXT
Normal file
103
NQ/data/ORDER.TXT
Normal file
@ -0,0 +1,103 @@
|
||||
ORDERING INFO
|
||||
To order the full version of Quake (or any other id Software
|
||||
product) in North America, call our fulfillment center at 1-800-idgames
|
||||
(1-800-434-3627). Except as noted by our operators, you can expect
|
||||
Airborne Express afternoon delivery. The price for the full version
|
||||
of Quake (available on PC CDROM only) is $45, plus $5 shipping, for a
|
||||
total of $50. Our fulfillment center accepts Visa, Mastercard, and
|
||||
American Express. You can also fax, mail, or email your order using
|
||||
the attached forms. The fax number is (317) 361-3710 and the email
|
||||
address is idsoftware@stream.com. To prepay and order with a check
|
||||
by mail, send your check and the order form to:
|
||||
|
||||
id Software
|
||||
P.O. Box 4500
|
||||
Crawfordsville, IN 47933
|
||||
|
||||
To see an electronic catalog of our software, tshirts, hint books, and
|
||||
other merchandise available, check out the Shopping Maul section of our
|
||||
website at www.idsoftware.com.
|
||||
|
||||
INTERNATIONAL ORDERS
|
||||
Quake is available worldwide as a full retail product. To find out
|
||||
which local stores carry Quake and other id products, contact the
|
||||
following international affiliates:
|
||||
|
||||
Europe Australia
|
||||
GT Interactive Software Roadshow New Media
|
||||
1712 583791 (U.K.) 1 902 962000
|
||||
|
||||
Taiwan Singapore
|
||||
U.S. Summit Corporation Summit Co. (Singapore) Pte. Ltd.
|
||||
706-0660 273-9988
|
||||
|
||||
Malaysia Honk Kong
|
||||
Summit Co. (Malaysia) Sdn Bhd Tsun Tsun Trading Company
|
||||
757-2244 571-4231
|
||||
|
||||
Thailand Israel/Jordan/Lebanon/Egypt
|
||||
U.S. Summit Corp. (Overseas) Mirage Mulimedia
|
||||
374-3956 972 3 510 5764
|
||||
|
||||
If you are in a territory that cannot access 1(800)idgames, and you
|
||||
wish to order our products directly, you must place your order in
|
||||
writing to the fax, mail, or email addresses listed above under
|
||||
ORDERING INFO.
|
||||
|
||||
International phone orders will NOT be accepted. Unfortunately, due
|
||||
to international shipping costs, all international orders are sent
|
||||
out via US Mail. This means we cannot guarantee timeliness of delivery
|
||||
due to customs and other delays inherent to international shipping
|
||||
______________________________________________________________________
|
||||
ORDER FORM -- USE THIS FORM TO FAX , MAIL OR EMAIL YOUR ORDER.
|
||||
|
||||
id Software Order Center Date ______________
|
||||
PO BOX 4500 Phone: 1800 id games
|
||||
Crawfordsville, IN 47933 Fax: (317) 361-3710
|
||||
idsoftware@stream.com
|
||||
|
||||
|
||||
Product List and Prices in U.S. Currency: (check items)
|
||||
|
||||
Quake (CD ROM only) $45 ____
|
||||
The Ultimate DOOM (Mac version available – must specify) $25 ____
|
||||
DOOM II (Mac version available – must specify) $40 ____
|
||||
Master Levels for DOOM II (CD ROM only) $25 ____
|
||||
Final DOOM (CD ROM only) $40 ____
|
||||
DOOM Hint Book $15 ____
|
||||
Original DOOM Tshirt (S,M.L.XL) $13 ____
|
||||
The Ultimate DOOM Tshirt (XXL only) $13 ____
|
||||
Final DOOM Tshirt $13 ____
|
||||
Heretic:Shadow of the Serpent Riders (CD ROM only) $40 ____
|
||||
Heretic Hint Book $15 ____
|
||||
Hexen:Beyond Heretic (Mac version available – must specify) $40 ____
|
||||
Hexen:Deathkings of the Dark Citadel (CD ROM only) $25 ____
|
||||
Hexen Hint Book $15 ____
|
||||
Hexen Tshirt (XXL only) $13 ____
|
||||
Wolfenstein 3D (PC CD only) $20 ____
|
||||
Commander Keen (3.5 disk only) $15 ____
|
||||
|
||||
Order total: $______
|
||||
|
||||
Name: Age (optional):
|
||||
|
||||
Form of payment (check, money order, or credit card):
|
||||
|
||||
Credit card number: Expiration Date:
|
||||
|
||||
Exact mailing address:______________________________________
|
||||
_______________________________________
|
||||
_______________________________________
|
||||
_______________________________________
|
||||
|
||||
Phone: Fax: Email:
|
||||
|
||||
Shipping: US orders-$5.00 first product/$2.00 each additional
|
||||
(allow 3-5 business days)
|
||||
|
||||
International shipping for prepaid orders are via US Mail, and
|
||||
we cannot guarantee the time it will take to arrive.
|
||||
|
||||
*Prices subject to change
|
||||
|
||||
|
456
NQ/data/README.TXT
Normal file
456
NQ/data/README.TXT
Normal file
@ -0,0 +1,456 @@
|
||||
Welcome to Quake!
|
||||
|
||||
This file details how to get Quake running on your system and what to do
|
||||
if you have problems. We would like to thank Gandalf Technologies, Inc and
|
||||
MPath Interactive for the use of their technology. We would also like to
|
||||
thank Trent Reznor and Nine Inch Nails for their tremendous contributions
|
||||
to Quake's entire audio portion.
|
||||
|
||||
The NIN logo is a Registered Trademark licensed to Nothing Interactive, Inc.
|
||||
All Rights Reserved.
|
||||
|
||||
Quake System Requirements
|
||||
-------------------------
|
||||
IBM PC and Compatibles
|
||||
Pentium processor or better
|
||||
VGA Compatible Display or better
|
||||
8MB RAM minimum, 16MB recommended (16 MB required for running under Win95)
|
||||
CD-ROM drive Required
|
||||
MS-DOS 5.0 or better or Windows 95 (does NOT run under Windows NT)
|
||||
Hard Drive (30MB for Shareware, 80 MB for Registered)
|
||||
|
||||
*** IMPORTANT!: Quake requires a floating point processor.
|
||||
Systems that do not have an FPU installed will not run Quake -- at all.
|
||||
|
||||
*** IMPORTANT Video Adapter Note! ***
|
||||
On some ATI Mach32 cards, Quake can come up with a garbled video display.
|
||||
This is due to a problem with the card in which 320x200 mode isn't
|
||||
initialized correctly. Workarounds include:
|
||||
|
||||
1) If running from Windows, start Quake from an icon, or from a windowed
|
||||
(not fullscreen) MS-DOS prompt. If Quake is already running and has
|
||||
the garbled screen, press Alt-Enter twice to switch to the desktop and
|
||||
back to fullscreen, and the screen will display properly.
|
||||
|
||||
2) If running from DOS, either put the line
|
||||
|
||||
vid_mode 1
|
||||
|
||||
in id1\autoexec.cfg, or, typing blind, press tilde ('~') to bring down
|
||||
the console, type
|
||||
|
||||
vid_mode 1<enter>
|
||||
|
||||
and the screen will display properly.
|
||||
|
||||
========================================================================
|
||||
Here are the text files included with the shareware release of Quake and
|
||||
what they are:
|
||||
|
||||
README.TXT This file
|
||||
TECHINFO.TXT Technical information on Quake's subsystems and
|
||||
their advanced use.
|
||||
MANUAL.TXT Text version of the printed game manual
|
||||
LICINFO.TXT Info on the various license files included with Quake
|
||||
SLICNSE.TXT Shareware Quake end-user license
|
||||
ORDER.TXT How to order Quake
|
||||
HELP.TXT How to get help with Quake
|
||||
|
||||
Here are the text files included with the registered version of Quake and
|
||||
what they are:
|
||||
|
||||
README.TXT This file
|
||||
TECHINFO.TXT Technical information on Quake's subsystems and
|
||||
their advanced use.
|
||||
MANUAL.TXT Text version of the printed game manual
|
||||
LICINFO.TXT Info on the various license files included with Quake
|
||||
RLICNSE.TXT Registered Quake end-user license
|
||||
COMEXP.TXT Commercial exploitation agreement
|
||||
ORDER.TXT How to order Quake
|
||||
HELP.TXT How to get help with Quake
|
||||
|
||||
|
||||
Running Quake
|
||||
-------------
|
||||
|
||||
DOS: To launch Quake from the DOS Prompt, go to the Quake directory and
|
||||
simply type "QUAKE" <ENTER>. (no quotes)
|
||||
|
||||
Windows 95: To launch Quake in single player mode, double click on the file
|
||||
QUAKE.EXE From Windows Explorer. To run Quake in Multi-Player mode using
|
||||
the TCP/IP protocol, first check your network settings to ensure the
|
||||
protocol is installed, then double click on the Q95.BAT file to launch the
|
||||
game. In this version (v0.91) there is a minor bug that will cause the
|
||||
Q95.BAT file to exit the first time you run it, without running Quake.
|
||||
Merely double-click on that file again and it will work.
|
||||
|
||||
Audio Setup
|
||||
-----------
|
||||
|
||||
When using a Sound Card with Quake, there are a few setup steps which must
|
||||
be taken. First, the "BLASTER" environment variable setting must be in your
|
||||
autoexec.bat (or you can type it in manually from the MS-DOS command prompt).
|
||||
Running the Sound Blaster utility diagnose.exe will automatically configure
|
||||
your sound card and put this statement in your autoexec.bat file for you.
|
||||
A typical blaster setting looks like this (although yours may vary):
|
||||
|
||||
SET BLASTER=A220 I5 D1 H5 P330 T6
|
||||
|
||||
If you want to play the audio track from the CD-ROM while playing Quake,
|
||||
you must ensure that the audio cable from the CD-ROM is connected to the
|
||||
sound card.
|
||||
|
||||
If you think your sound card is setup properly and it STILL doesn't work,
|
||||
check to make sure that your BLASTER environment variable contains the
|
||||
high DMA setting (H5 in the above example).
|
||||
|
||||
If you don't get sound while trying to play the audio track, check to see
|
||||
if a small cable goes from the back of your CD-ROM player directly to your
|
||||
sound card. If the CD-ROM audio cable is connected to your sound board (or
|
||||
the motherboard in some cases) and you STILL don't hear CD Audio coming from
|
||||
your speakers, make sure the MIXER program has the CD volume turned up.
|
||||
You will also need to run the CD-ROM driver MSCDEX.EXE. Here is an example
|
||||
of the files you should see (yours probably will vary) listed in your
|
||||
CONFIG.SYS and AUTOEXEC.BAT (explanation is in parentheses):
|
||||
|
||||
CONFIG.SYS:
|
||||
|
||||
DEVICE=C:\PROSCSI\CDROM.SYS /D:PROCD01 (CD-ROM driver)
|
||||
|
||||
AUTOEXEC.BAT:
|
||||
|
||||
SET BLASTER=A220 I5 D1 H5 P330 T6 (sound environment variable setting)
|
||||
C:\WINDOWS\COMMAND\MSCDEX.EXE /D:PROCD01 /L:D (CD-ROM driver)
|
||||
|
||||
===================================================
|
||||
UltraSound MAX and UltraSound PnP Support for Quake
|
||||
===================================================
|
||||
|
||||
Before running Quake, make sure that your sound card works and your
|
||||
environment variables are set correctly.
|
||||
|
||||
Other UltraSound Cards (ACE & Classic)
|
||||
--------------------------------------
|
||||
These drivers are not for the UltraSound ACE or UltraSound Classic
|
||||
sound cards. We have heard mixed reports that MegaEm or SBOS
|
||||
have a chance of working with the UltraSound Classic but there is a
|
||||
short sound F/X delay.
|
||||
|
||||
UltraSound PnP and PnP Pro
|
||||
--------------------------
|
||||
You must make sure that you do NOT have IWSBOS or MegaEm loaded.
|
||||
|
||||
Setup
|
||||
-----
|
||||
Quake will automatically detect that the UltraSound Max or PnP
|
||||
are installed. It does this by looking at the SET INTERWAVE (PnP)
|
||||
and SET ULTRA16 (Max) environment variables.
|
||||
|
||||
Quake will use the settings found on the SET ULTRASND/ULTRA16 (Max)
|
||||
and in the IW.INI (PnP) file to determine what port settings to use.
|
||||
|
||||
Troubleshooting Windows 95 (DOS Box)
|
||||
------------------------------------
|
||||
We recommend that you restart your computer in MS-DOS Mode. DOS Box
|
||||
may or may not work, so use at your own risk.
|
||||
|
||||
CD Audio Input
|
||||
--------------
|
||||
If you have not already enabled CD audio output by default you will
|
||||
need to enable it. For the UltraSound MAX you can run "ULTRINIT -EC".
|
||||
For the UltraSound PnP you will need to enable the CD audio output
|
||||
in Win'95 and then restart your computer into MS-DOS.
|
||||
|
||||
===================================================
|
||||
Mouse Setup
|
||||
-----------
|
||||
|
||||
If you are going to use a mouse when playing Quake, you will need to load
|
||||
your mouse driver. This should go in the AUTOEXEC.BAT file as well. Here
|
||||
is an example:
|
||||
|
||||
C:\LOGITECH\MOUSE\MOUSE.EXE (mouse driver)
|
||||
|
||||
|
||||
Booting Clean
|
||||
-------------
|
||||
|
||||
If you are going to be running Quake with only 8 megabytes of RAM, it is best
|
||||
to boot clean . You eliminate unwanted utilities or applications from taking
|
||||
up valuable memory, without having to alter your regular AUTOEXEC.BAT and
|
||||
CONFIG.SYS. Booting clean can be done in one of two ways. If you have
|
||||
MS-DOS version 6.xx, booting clean is as simple a pressing the shift key
|
||||
when you see the words "Starting MS-DOS". If you have MS-DOS ver 5.xx you
|
||||
will need to make a system disk.
|
||||
|
||||
To make a boot disk, type the following from the MS-DOS command prompt:
|
||||
|
||||
FORMAT A: /S
|
||||
|
||||
1. Make sure that this is a disk you wish to erase.
|
||||
2. This disk absolutely HAS to be formatted in the A: drive.
|
||||
|
||||
To use the system disk, place the disk in the A: drive and reset the
|
||||
computer.
|
||||
|
||||
NOTE: If your sound card requires a driver to be loaded, or you will be
|
||||
using a mouse, or you will be using Quake's CD audio feature, the system
|
||||
disk will need to have a CONFIG.SYS and AUTOEXEC.BAT that load the
|
||||
appropriate drivers.
|
||||
|
||||
Creating a Quake Shortcut
|
||||
|
||||
As an alternative to making a Boot Disk, Windows 95 users can create a
|
||||
Quake Shortcut. By double clicking onthis shortcut, Windows 95 will reboot
|
||||
in MS-DOS mode and install only the desired drivers, giving you the same
|
||||
results as using a Boot Disk. To create a Quake Shortcut, do the following:
|
||||
|
||||
1. Using Explorer, right click and drag the file QUAKE.EXE, from the Quake
|
||||
directory, to your desktop. Windows 95 will make an MS-DOS Icon titled
|
||||
"Shortcut to quake".
|
||||
2. Right click on the new icon, and from the menu that pops up, choose
|
||||
"Properties". Then choose the "Program" tab at the top.
|
||||
3. Now click on the "Advanced..." button near the bottom. The "Advanced
|
||||
Program Settings" window should appear.
|
||||
4. Select the "MS-DOS mode" check box and the "Specify a new MS-DOS
|
||||
configuration" option button.
|
||||
5. Now simply fill in the "CONFIG.SYS for MS-DOS mode:" and "AUTOEXEC.BAT
|
||||
for MS-DOS mode:" boxes with the same sound, CD-ROM and mouse settings as
|
||||
mentioned above in the Boot Disks section.
|
||||
6. Click on "OK" when you are finished. If you wish, you can change your
|
||||
Quake Shortcut Icon to something a little more exciting by clicking on
|
||||
"Change Icon...".
|
||||
7. To finish, click on "OK" again.
|
||||
8. You can rename your Quake Shortcut by right clicking on the shortcut
|
||||
icon, choosing "Rename" and typing in the new name.
|
||||
|
||||
|
||||
======================================================
|
||||
== Known Problems ==
|
||||
======================================================
|
||||
|
||||
Problem: Zombies sometime get stuck on the ground and connot get back up.
|
||||
(You can still hear them, but you cannot kill them. This bug makes it
|
||||
impossible to get 100% kills on whatever level it occurs on.)
|
||||
Solution: There is no workaround for this bug.
|
||||
|
||||
Problem: It is sometimes possible for the player to get stuck in a room or
|
||||
in a wall.
|
||||
Solution: If you get stuck, use the 'kill' console command. It is a good
|
||||
idea to save your game often.
|
||||
|
||||
Problem: View centering problems. Sometimes during a game, the view will not
|
||||
center properly. The end result is the player view looking up torwards the
|
||||
ceiling while walking.
|
||||
Solution: Exit to the next level or use the 'kill' console command..
|
||||
|
||||
|
||||
======================================================
|
||||
== Troubleshooting ==
|
||||
======================================================
|
||||
|
||||
If Quake fails to start up, or has problems not addressed elsewhere in the
|
||||
documentation, try the -safe command line switch, which disables a number
|
||||
of parts of Quake that can be problems if there are hardware or configuration
|
||||
problems. The -safe command line switch is equivalent to -stdvid, -nosound,
|
||||
-nonet, and -nocdaudio together. Those four switches do the following:
|
||||
|
||||
-stdvid: disables VESA video modes.
|
||||
|
||||
-nosound: disables sound card support.
|
||||
|
||||
-nonet: disables network card support.
|
||||
|
||||
-nocdaudio: disables CD audio support.
|
||||
|
||||
If -safe makes the problem go away, try using each of the switches
|
||||
individually to isolate the area in which you're experiencing the problem,
|
||||
then either correct the configuration or hardware problem or play Quake with
|
||||
that functionality disabled.
|
||||
|
||||
If you still have problems, try booting clean in conjunction with
|
||||
the -safe command line parameter. For information on booting clean, refer
|
||||
to the "Booting Clean" section above.
|
||||
|
||||
If you experience page faults while running Quarterdeck's QDPMI DPMI server,
|
||||
this is caused by a bug in QDPMI. Workarounds: Remove QDPMI from CONFIG.SYS,
|
||||
issue the command QDPMI OFF before running QUAKE, or get the update patch
|
||||
for QDPMI from Quarterdeck. You may be running QDPMI without knowing it if
|
||||
you have QEMM installed, because it can be installed as part of the QEMM
|
||||
installation.
|
||||
|
||||
|
||||
Technical Support
|
||||
-----------------
|
||||
|
||||
If you are having trouble installing or running Quake you can receive
|
||||
technical support by sending e-mailing to support@idsoftware.com. You can
|
||||
also refer to our web page, www.idsoftware.com, or call 1-800-idgames.
|
||||
|
||||
When sending support e-mail, cut and paste the following into your e-mail
|
||||
message and fill in the blanks:
|
||||
|
||||
Date:
|
||||
Name:
|
||||
Phone number:
|
||||
E-mail address: (please include this, we redirect tons of mail)
|
||||
Game Title:
|
||||
Version #:
|
||||
Operating system (i.e., DOS 6.0 or Windows 95):
|
||||
Computer type:
|
||||
BIOS date:
|
||||
BIOS version:
|
||||
Processor type:
|
||||
Processor speed:
|
||||
Do you program at school/work?
|
||||
Do you provide tech. support at school/work?
|
||||
Please state the problem you encountered:
|
||||
Please state how to reproduce the problem:
|
||||
|
||||
If program crashed with nasty undecipherable techno-garbage, please
|
||||
look for the eight-digit hex number which comes after "eip="
|
||||
and write it down here:
|
||||
|
||||
** NOTE: If you are sending a bug report, PLEASE refer to the TECHINFO.TXT
|
||||
file for the correct form and procedures.
|
||||
|
||||
|
||||
======================================================
|
||||
== Version History ==
|
||||
======================================================
|
||||
v1.01 -- Bugs fixed
|
||||
------------------------------------------------------
|
||||
* Fixed modem code
|
||||
* Fixed fraglimit & timelimit
|
||||
* Added NOEXIT cvar (so no one can exit a level)
|
||||
------------------------------------------------------
|
||||
v1.00 -- Bugs fixed
|
||||
------------------------------------------------------
|
||||
* Gravis Ultrasound audio support (still has bugs)
|
||||
* More deathmatch start spots on E1M6 and END
|
||||
* Print server version and PROG CRC on connect
|
||||
* -dedicated starts start.map if nothing else specified
|
||||
* fixed lookspring function during net game
|
||||
* fixed rare crash during long running dedicated server
|
||||
------------------------------------------------------
|
||||
v0.94 -- Bugs fixed / Features added -- LIMITED BETA VERSION
|
||||
------------------------------------------------------
|
||||
* Totally rewritten menus
|
||||
* New lighting model with overbrighting
|
||||
* Parsed lowercase BLASTER parms
|
||||
* Better Sound Blaster shutdown code
|
||||
* Rewrote BLASTER initialization
|
||||
* Fixed DMA channel 0 bugs
|
||||
* Added SBPro 8 stereo setup
|
||||
* Fix delayed sound on 8 bit Sound Blasters
|
||||
* Fixed speed key affecting angle-turning from keyboard
|
||||
* Fixed "no such Alias frame" bugs
|
||||
* Fixed Zombie not getting up bug
|
||||
* Checked for very high joystick values, signalling a failed read
|
||||
* Unstuck jumping Fiends and Spawn
|
||||
* Fixed large BModels blinking out in complex areas
|
||||
* Fixed s_localsound with no sound started
|
||||
* Saved spawn parms in savegame
|
||||
* Fixed screenshot save location
|
||||
* Bind with no arguments no longer clears value
|
||||
* Allow console in intermission / finale
|
||||
* Fixed false gib messages
|
||||
* Full-screen TAB scoreboard in DeathMatch
|
||||
* Fixed "+playdemo <demo>" from command line
|
||||
* Trapped overflow in sizebuf messages
|
||||
* Moveup / movedown in water!
|
||||
* Fixed-up Talk command
|
||||
* Added unsupported crosshair option ("crosshair 1" from console)
|
||||
* Colored chat messages with notify sound
|
||||
* Fixed "connect during intermission" bug
|
||||
* Changelevel while demos running no longer crashes
|
||||
* Fixed changelevel with no map left up loading screen
|
||||
* Fixed long names entered from the console causing crash
|
||||
* Stopped demos changing while in the menus
|
||||
|
||||
* Fixed modem initialization from menu
|
||||
* Fixed serial reliable stream getting stalled
|
||||
* Serial/modem code fixes
|
||||
16550a lost transmit buffer empty interrupts
|
||||
fixed sometimes processing interrupts from com1 when using com2
|
||||
added com3/com4 support from menus
|
||||
fixed first character of modem init not getting sent
|
||||
saved serial/modem settings in config.cfg
|
||||
* Fixed name and colors not always sent to server at startup
|
||||
* Fixed "stopdemo" crashing the system when there wasn't a demo playing
|
||||
* Added server's TCP/IP and IPX addresses (if available) to status command
|
||||
|
||||
* In 0.92, an additional check for a usable VESA video mode was added;
|
||||
the numpages field was verified to be greater than 0, and no mode was
|
||||
supported that had numpages set to 0 (which indicates that there's not
|
||||
enough video memory for that mode). ATI's VESA driver, m64vbe,
|
||||
reports 0 for numpages, so VESA video modes that were available in 0.91
|
||||
were no longer available in 0.92. This extra numpages check has
|
||||
been removed.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
v0.93 -- Never officially released; internal testing only.
|
||||
-----------------------------------------------------------------------
|
||||
v0.92 -- Bugs fixed
|
||||
-----------------------------------------------------------------------
|
||||
Typing long strings in the hostname or modem init field in the menus caused
|
||||
crashes.
|
||||
|
||||
Under Win95 IPX was detected but not functional, resulting in the game
|
||||
exiting to DOS.
|
||||
|
||||
If -nosound, got "S_LocalSound: can't cache" on every keypress in the menu.
|
||||
|
||||
When vid_nopageflip was set to 1 in VESA modes, going underwater resulted in
|
||||
only the upper left corner of the drawing area being updated.
|
||||
|
||||
The single player scoreboard (tab) printed text incorrectly in all modes
|
||||
greater than 320 pixels wide.
|
||||
|
||||
On network connections that dropped packets, the reliable message stream
|
||||
could get stopped up, resulting in frag counts and talk messages no longer
|
||||
being delivered, although game movement continued.
|
||||
|
||||
The com port settings from the menu were getting saved & restored but
|
||||
not used.
|
||||
|
||||
Direct serial connections did not work with slist.
|
||||
|
||||
Quake now checks the vesa information for hardware incabable of page-flipping.
|
||||
|
||||
Menu sound sometimes didn't play.
|
||||
|
||||
Q95 (qlaunch.exe) frequently failed to execute on the first attempt.
|
||||
|
||||
Q95 (quakeudp.dll) was running out of buffers when running a server.
|
||||
|
||||
Teams were not being set according to pants colors.
|
||||
|
||||
|
||||
Joystick notes
|
||||
--------------
|
||||
Your joystick must be plugged in when Quake is launched.
|
||||
|
||||
If you have a joystick plugged in, but don't want to use it in Quake
|
||||
(it slows the game down a few percent), or you have weird hardware that
|
||||
doesn't like being tested as a joystick add "-nojoy" to your Quake
|
||||
command line.
|
||||
|
||||
You can turn off joystick reading during the game by typing "joystick 0" at
|
||||
the Quake command console.
|
||||
|
||||
You MUST configure your buttons from the configure keys menu before they will
|
||||
work. There is no default configuration.
|
||||
|
||||
If your joystick or interface card improperly sets the third or fourth
|
||||
joystick buttons, type "joybuttons 2" at the quake console or in your
|
||||
.CFG file.
|
||||
|
||||
The "mlook" button command now lets the joystick as well as the mouse control
|
||||
pitch angles.
|
||||
|
||||
The "sidestep" buttom command works on joysticks as with mice and keyboard
|
||||
movement.
|
||||
|
||||
The "invert mouse up/down" menu option also inverts the joystick pitch
|
||||
direction.
|
204
NQ/data/RLICNSE.TXT
Normal file
204
NQ/data/RLICNSE.TXT
Normal file
@ -0,0 +1,204 @@
|
||||
REGISTERED VERSION: QUAKE
|
||||
LIMITED USE SOFTWARE LICENSE AGREEMENT
|
||||
|
||||
This Limited Use Software License Agreement (the
|
||||
"Agreement") is a legal agreement between you, the end-user, and Id
|
||||
Software, Inc. ("ID"). By continuing the installation of this game
|
||||
program, by loading or running the game, or by placing or copying
|
||||
the game program onto your computer hard drive, you are agreeing to
|
||||
be bound by the terms of this Agreement. If you do not agree to
|
||||
the terms of this Agreement, promptly return the game program and
|
||||
the accompanying items (including all written materials), along
|
||||
with your receipt to the place from where you obtained them for a
|
||||
full refund.
|
||||
|
||||
ID SOFTWARE LICENSE
|
||||
|
||||
1. Grant of License. ID grants to you the limited
|
||||
right to use one (1) copy of the enclosed or foregoing game program
|
||||
(the "Software") on a single computer. You have no ownership or
|
||||
proprietary rights in or to the Software or the written materials
|
||||
accompanying the Software. For purposes of this section, "use"
|
||||
means loading the Software into RAM, as well as installation on a
|
||||
hard disk or other storage device. You may create a map editor,
|
||||
modify maps and make your own maps (collectively referenced as the
|
||||
"Permitted Derivative Works") for the Software. Permitted
|
||||
Derivative Works may not be sold, whether by you or by any other
|
||||
person or entity, but you may exchange the Permitted Derivative
|
||||
Works at no charge amongst other end-users. The Software, together
|
||||
with any archive copy thereof, shall be either returned to ID or
|
||||
destroyed when no longer used in accordance with this Agreement, or
|
||||
when the right to use the Software is terminated. You agree that
|
||||
the Software will not be shipped, transferred or exported into any
|
||||
country in violation of the U.S. Export Administration Act (or any
|
||||
other law governing such matters) and that you will not utilize, in
|
||||
any other manner, the Software in violation of any applicable law.
|
||||
|
||||
2. Commercial Use is Prohibited. Except as provided in
|
||||
paragraph 5. hereinbelow in regard to the Software, under no
|
||||
circumstances shall you, the end-user, be permitted, allowed or
|
||||
authorized to commercially exploit the Software, any data
|
||||
comprising the Software. Neither you nor anyone at your direction
|
||||
shall do any of the following acts (any such acts shall be deemed
|
||||
void and a breach of this Agreement) with regard to the Software,
|
||||
or any portion thereof, such as a screen display or a screenshot:
|
||||
|
||||
a. Rent the Software;
|
||||
|
||||
b. Sell the Software;
|
||||
|
||||
c. Lease or lend the Software;
|
||||
|
||||
d. Offer the Software on a pay-per-play basis;
|
||||
|
||||
e. Distribute, by electronic means or otherwise, the
|
||||
Software for money or any other consideration; or
|
||||
|
||||
f. In any other manner and through any medium
|
||||
whatsoever commercially exploit the Software or use
|
||||
the Software for any commercial purpose.
|
||||
|
||||
3. Additional Prohibited Uses. Neither you nor anyone
|
||||
at your direction shall take the following action in regard to the
|
||||
Software, or any portion thereof, such as a screen display or a
|
||||
screenshot:
|
||||
|
||||
a. Modify, disassemble, reverse engineer or decompile
|
||||
the Software;
|
||||
|
||||
b. Translate the Software;
|
||||
|
||||
c. Reproduce the Software;
|
||||
|
||||
d. Publicly display the Software;
|
||||
|
||||
e. Prepare derivative works based upon the Software
|
||||
(except Permitted Derivative Works); or
|
||||
|
||||
f. Distribute, by electronic means or otherwise, the
|
||||
Software.
|
||||
|
||||
4. Use of Other Material is Prohibited. Use, in any manner, of
|
||||
the trademarks, such as Quake(tm) and the NIN(r) logo, logos, symbols,
|
||||
art work, images, screen displays or screenshots, sound effects, music,
|
||||
and other such material contained within, generated by or relating to
|
||||
the Software is prohibited.
|
||||
|
||||
5. To Receive Permission to Commercially Exploit. If
|
||||
you desire to commercially exploit the Software, you may execute
|
||||
the Commercial Exploitation License Agreement for QUAKE (the
|
||||
"License") contained within the QUAKE install package and forward
|
||||
the original License to Id Software at the address noted therein.
|
||||
Please note that ID may refuse your request and not sign the
|
||||
License in ID's sole discretion.
|
||||
|
||||
6. Restrictions Apply to Third Parties. The
|
||||
prohibitions and restrictions described herein apply to anyone in
|
||||
possession of the Software and/or Permitted Derivative Works.
|
||||
|
||||
7. Copyright. The Software and all copyrights related
|
||||
thereto (including all characters and other images generated by the
|
||||
Software or depicted in the Software) is owned by ID and is protected
|
||||
by United States copyright laws and international treaty provisions.
|
||||
You must treat the Software like any other copyrighted material,
|
||||
except that you may either (a) make one copy of the Software solely
|
||||
for back-up or archival purposes, or (b) transfer the Software to a
|
||||
single hard disk provided you keep the original solely for back-up or
|
||||
archival purposes. You may not otherwise reproduce, copy or disclose
|
||||
to others, in whole or in any part, the Software. You may not copy
|
||||
the written materials accompanying the Software. The same
|
||||
restrictions and prohibitions regarding your use of the Software as
|
||||
provided in this Agreement apply to your use of the written materials
|
||||
accompanying the Software. The written materials are owned by ID and
|
||||
are protected by United States copyright laws and international
|
||||
treaties. You agree to use your best efforts to see that any user of
|
||||
the Software licensed hereunder complies with this Agreement.
|
||||
|
||||
8. Limited Warranty. ID warrants that if properly
|
||||
installed and operated on a computer for which it is designed, the
|
||||
Software will perform substantially in accordance with the
|
||||
accompanying written materials for a period of ninety (90) days
|
||||
from the date of purchase of the Software. ID's entire liability
|
||||
and your exclusive remedy shall be, at ID's option, either (a)
|
||||
return of the price paid or (b) repair or replacement of the
|
||||
Software that does not meet ID's Limited Warranty. To make a
|
||||
warranty claim, return the Software to the point of purchase,
|
||||
accompanied by proof of purchase, your name, your address, and a
|
||||
statement of defect, or return the Software with the above
|
||||
information to ID. This Limited Warranty is void if failure of the
|
||||
Software has resulted in whole or in part from accident, abuse,
|
||||
misapplication or violation of this Agreement. Any replacement
|
||||
Software will be warranted for the remainder of the original
|
||||
warranty period or thirty (30) days from your receipt of the
|
||||
replacement software, whichever is longer. This warranty allocates
|
||||
risks of product failure between Licensee and ID. ID's product
|
||||
pricing reflects this allocation of risk and the limitations of
|
||||
liability contained in this warranty.
|
||||
|
||||
9. NO OTHER WARRANTIES. ID DISCLAIMS ALL OTHER
|
||||
WARRANTIES, BOTH EXPRESS IMPLIED, INCLUDING BUT NOT LIMITED TO,
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
|
||||
PURPOSE WITH RESPECT TO THE SOFTWARE AND THE ACCOMPANYING WRITTEN
|
||||
MATERIALS. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL RIGHTS.
|
||||
YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO
|
||||
JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE
|
||||
SOFTWARE WILL BE UNINTERRUPTED, ERROR FREE OR MEET LICENSEE'S
|
||||
SPECIFIC REQUIREMENTS. THE WARRANTY SET FORTH ABOVE IS IN LIEU OF
|
||||
ALL OTHER EXPRESS WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS,
|
||||
EMPLOYEES, DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO
|
||||
MAKE MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON
|
||||
BEHALF OF ID. ADDITIONAL STATEMENTS SUCH AS DEALER ADVERTISING OR
|
||||
PRESENTATIONS, WHETHER ORAL OR WRITTEN, DO NOT CONSTITUTE
|
||||
WARRANTIES BY ID AND SHOULD NOT BE RELIED UPON.
|
||||
|
||||
10. Exclusive Remedies. You agree that your exclusive
|
||||
remedy against ID, its affiliates, contractors, suppliers, and
|
||||
agents for loss or damage caused by any defect or failure in the
|
||||
Software regardless of the form of action, whether in contract,
|
||||
tort, including negligence, strict liability or otherwise, shall be
|
||||
the return of the purchase price paid or replacement of the
|
||||
Software. This Agreement shall be construed in accordance with and
|
||||
governed by the laws of the State of Texas. Copyright and other
|
||||
proprietary matters will be governed by United States laws and
|
||||
international treaties. IN ANY CASE, ID SHALL NOT BE LIABLE FOR
|
||||
LOSS OF DATA, LOSS OF PROFITS, LOST SAVINGS, SPECIAL, INCIDENTAL,
|
||||
CONSEQUENTIAL, INDIRECT OR OTHER SIMILAR DAMAGES ARISING FROM
|
||||
BREACH OF WARRANTY, BREACH OF CONTRACT, NEGLIGENCE, OR OTHER LEGAL
|
||||
THEORY EVEN IF ID OR ITS AGENT HAS BEEN ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. Some
|
||||
jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so the above limitation or
|
||||
exclusion may not apply to you.
|
||||
|
||||
11. General Provisions. Neither this Agreement nor any
|
||||
part or portion hereof shall be assigned, sublicensed or otherwise
|
||||
transferred by you. Should any provision of this Agreement be held
|
||||
to be void, invalid, unenforceable or illegal by a court, the
|
||||
validity and enforceability of the other provisions shall not be
|
||||
affected thereby. If any provision is determined to be
|
||||
unenforceable, you agree to a modification of such provision to
|
||||
provide for enforcement of the provision's intent, to the extent
|
||||
permitted by applicable law. Failure of a party to enforce any
|
||||
provision of this Agreement shall not constitute or be construed as
|
||||
a waiver of such provision or of the right to enforce such
|
||||
provision. If you fail to comply with any terms of this Agreement,
|
||||
YOUR LICENSE IS AUTOMATICALLY TERMINATED.
|
||||
|
||||
YOU ACKNOWLEDGE THAT YOU HAVE READ THIS AGREEMENT, THAT YOU
|
||||
UNDERSTAND THIS AGREEMENT, AND UNDERSTAND THAT BY CONTINUING THE
|
||||
INSTALLATION OF THE SOFTWARE, BY LOADING OR RUNNING THE SOFTWARE, OR
|
||||
BY PLACING OR COPYING THE SOFTWARE ONTO YOUR COMPUTER HARD DRIVE, YOU
|
||||
AGREE TO BE BOUND BY THIS AGREEMENT'S TERMS AND CONDITIONS. YOU
|
||||
FURTHER AGREE THAT, EXCEPT FOR WRITTEN SEPARATE AGREEMENTS BETWEEN ID
|
||||
AND YOU, THIS AGREEMENT IS A COMPLETE AND EXCLUSIVE STATEMENT OF THE
|
||||
RIGHTS AND LIABILITIES OF THE PARTIES. THIS AGREEMENT SUPERSEDES ALL
|
||||
PRIOR ORAL AGREEMENTS, PROPOSALS OR UNDERSTANDINGS, AND ANY OTHER
|
||||
COMMUNICATIONS BETWEEN ID AND YOU RELATING TO THE SUBJECT MATTER OF
|
||||
THIS AGREEMENT.
|
||||
|
||||
June 21, 1996
|
||||
|
||||
REGISTERED VERSION: QUAKE LIMITED USE SOFTWARE LICENSE AGREEMENT Page 4
|
||||
(DWC:dw:3406.0024:DWC\doc:1164)
|
||||
|
||||
|
175
NQ/data/SLICNSE.TXT
Normal file
175
NQ/data/SLICNSE.TXT
Normal file
@ -0,0 +1,175 @@
|
||||
SHAREWARE VERSION: QUAKE
|
||||
LIMITED USE SOFTWARE LICENSE AGREEMENT
|
||||
|
||||
This Limited Use Software License Agreement (the "Agreement") is a
|
||||
legal agreement between you, the end-user, and id Software, Inc.
|
||||
("ID"). By continuing the installation of this game program, by
|
||||
loading or running the game, or by placing or copying the game
|
||||
program onto your computer hard drive, you are agreeing to be bound
|
||||
by the terms of this Agreement.
|
||||
|
||||
ID SOFTWARE LICENSE
|
||||
|
||||
1. Grant of License. ID grants to you the limited right to use
|
||||
one (1) copy of the enclosed or foregoing Id Software game program
|
||||
(the "Software"), which is the shareware version or episode one of
|
||||
the game program. For purposes of this section, "use" means loading
|
||||
the Software into RAM, as well as installation on a hard disk or
|
||||
other storage device. You agree that the Software will not be
|
||||
shipped, transferred or exported into any country in violation of
|
||||
the U.S. Export Administration Act (or any other law governing such
|
||||
matters) and that you will not utilize, in any other manner, the
|
||||
Software in violation of any applicable law.
|
||||
|
||||
2. Commercial Use is Prohibited. Under no circumstances shall
|
||||
you, the end-user, be permitted, allowed or authorized to
|
||||
commercially exploit the Software, or any portion thereof, such
|
||||
as a screen display or a screenshot. Neither you nor anyone at your
|
||||
direction shall do any of the following acts:
|
||||
|
||||
a. Rent the Software;
|
||||
|
||||
b. Sell the Software;
|
||||
|
||||
c. Lease or lend the Software;
|
||||
|
||||
d. Offer the Software on a pay-per-play basis;
|
||||
|
||||
e. Distribute the Software for money or any other
|
||||
consideration; or
|
||||
|
||||
f. In any other manner and through any medium
|
||||
whatsoever commercially exploit the Software or use
|
||||
the Software for any commercial purpose.
|
||||
|
||||
3. Additional Prohibited Uses. Neither you, nor anyone at your
|
||||
direction, shall take the following action in regard to the
|
||||
Software, or any portion thereof, such as a screen display or
|
||||
a screenshot:
|
||||
|
||||
a. Modify, disassemble, reverse engineer or decompile
|
||||
the Software;
|
||||
|
||||
b. Translate the Software;
|
||||
|
||||
c. Reproduce the Software;
|
||||
|
||||
d. Publicly display the Software; or
|
||||
|
||||
e. Prepare derivative works based upon the Software.
|
||||
|
||||
4. Use of Other Material is Prohibited. Use, in any manner, of
|
||||
the trademarks, such as Quake(tm) and the NIN(r) logo, logos, symbols,
|
||||
art work, images, screen displays or screenshots, sound effects, music,
|
||||
and other such material contained within, generated by or relating to
|
||||
the Software is prohibited.
|
||||
|
||||
5. Restrictions Apply to Third Parties. The prohibitions and
|
||||
restrictions described herein apply to anyone in possession of
|
||||
the Software.
|
||||
|
||||
6. Permitted Distribution. So long as this Agreement
|
||||
accompanies the Software at all times, ID grants to Providers the
|
||||
limited right to distribute, free of charge, except normal access
|
||||
fees, and by electronic means only, the Software; provided, however,
|
||||
the Software must be so electronically distributed only in a
|
||||
compressed format. The term "Providers," as used in the foregoing
|
||||
sentence, shall mean persons whose business it is to provide
|
||||
services on the Internet, on commercial online networks, or on the
|
||||
BBS. Anyone who receives the Software from a Provider shall be
|
||||
limited to all the terms and conditions of this Agreement. Further,
|
||||
ID grants to you, the end-user, the limited right to distribute,
|
||||
free of charge only, the Software as a whole.
|
||||
|
||||
7. Copyright. The Software is owned by ID and is protected by
|
||||
United States copyright laws and international treaty provisions.
|
||||
You must treat the Software like any other copyrighted material,
|
||||
except that you may make copies of the Software to give to other
|
||||
persons. You may not charge or receive any consideration from any
|
||||
other person for the receipt or use of the Software. You agree to
|
||||
use your best efforts to see that any user of the Software licensed
|
||||
hereunder complies with this Agreement.
|
||||
|
||||
8. Limited Warranty. ID warrants that if properly installed and
|
||||
operated on a computer for which it is designed, the Software will
|
||||
perform substantially in accordance with its designed purpose for a
|
||||
period of ninety (90) days from the date the Software is first
|
||||
obtained by an end-user. ID's entire liability and your exclusive
|
||||
remedy shall be, at ID's option, either (a) return of the retail
|
||||
price paid, if any, or (b) repair or replacement of the Software
|
||||
that does not meet ID's Limited Warranty. To make a warranty claim,
|
||||
return the Software to the point of purchase, accompanied by proof
|
||||
of purchase, your name, your address, and a statement of defect, or
|
||||
return the Software with the above information to ID. This Limited
|
||||
Warranty is void if failure of the Software has resulted in whole
|
||||
or in part from accident, abuse, misapplication or violation of this
|
||||
Agreement. Any replacement Software will be warranted for the
|
||||
remainder of the original warranty period or thirty (30) days,
|
||||
whichever is longer. This warranty allocates risks of product
|
||||
failure between Licensee and ID. ID's product pricing reflects this
|
||||
allocation of risk and the limitations of liability contained in
|
||||
this warranty.
|
||||
|
||||
9. NO OTHER WARRANTIES. ID DISCLAIMS ALL OTHER WARRANTIES,
|
||||
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A pARTICULAR PURPOSE
|
||||
WITH RESPECT TO THE SOFTWARE AND THE ACCOMPANYING WRITTEN MATERIALS,
|
||||
IF ANY. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL RIGHTS. YOU
|
||||
MAY HAVE OTHERS WHICH VARY FROM JURISDICTION TO JURISDICTION. ID
|
||||
DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE WILL BE
|
||||
UNINTERRUPTED, ERROR FREE OR MEET LICENSEE'S SPECIFIC REQUIREMENTS.
|
||||
THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS
|
||||
WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES,
|
||||
DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE
|
||||
MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF
|
||||
OF ID. ADDITIONAL STATEMENTS SUCH AS DEALER ADVERTISING OR
|
||||
PRESENTATIONS, WHETHER ORAL OR WRITTEN, DO NOT CONSTITUTE WARRANTIES
|
||||
BY ID AND SHOULD NOT BE RELIED UPON.
|
||||
|
||||
10. Exclusive Remedies. You agree that your exclusive remedy
|
||||
against ID, its affiliates, contractors, suppliers, and agents for
|
||||
loss or damage caused by any defect or failure in the Software
|
||||
regardless of the form of action, whether in contract,tort,
|
||||
including negligence, strict liability or otherwise, shall be the
|
||||
return of the retail purchase price paid, if any, or replacement of
|
||||
the Software. This Agreement shall be construed in accordance with
|
||||
and governed by the laws of the State of Texas. Copyright and other
|
||||
proprietary matters will be governed by United States laws and
|
||||
international treaties. IN ANY CASE, ID SHALL NOT BE LIABLE FOR LOSS
|
||||
OF DATA, LOSS OF PROFITS, LOST SAVINGS, SPECIAL, INCIDENTAL,
|
||||
CONSEQUENTIAL, INDIRECT OR OTHER SIMILAR DAMAGES ARISING FROM BREACH
|
||||
OF WARRANTY, BREACH OF CONTRACT, NEGLIGENCE, OR OTHER LEGAL THEORY
|
||||
EVEN IF ID OR ITS AGENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. Some jurisdictions do
|
||||
not allow the exclusion or limitation of incidental or consequential
|
||||
damages, so the above limitation or exclusion may not apply to you.
|
||||
|
||||
11. General Provisions. Neither this Agreement nor any part or
|
||||
portion hereof shall be assigned or sublicensed, except as described
|
||||
herein. Should any provision of this Agreement be held to be void,
|
||||
invalid, unenforceable or illegal by a court, the validity and
|
||||
enforceability of the other provisions shall not be affected thereby.
|
||||
If any provision is determined to be unenforceable, you agree to a
|
||||
modification of such provision to provide for enforcement of the
|
||||
provision's intent, to the extent permitted by applicable law. Failure
|
||||
of a party to enforce any provision of this Agreement shall not
|
||||
constitute or be construed as a waiver of such provision or of the
|
||||
right to enforce such provision. If you fail to comply with any terms
|
||||
of this Agreement, YOUR LICENSE IS AUTOMATICALLY TERMINATED.
|
||||
|
||||
YOU ACKNOWLEDGE THAT YOU HAVE READ THIS AGREEMENT, YOU UNDERSTAND
|
||||
THIS AGREEMENT, AND UNDERSTAND THAT BY CONTINUING THE INSTALLATION
|
||||
OF THE SOFTWARE, BY LOADING OR RUNNING THE SOFTWARE, OR BY PLACING
|
||||
OR COPYING THE SOFTWARE ONTO YOUR COMPUTER HARD DRIVE, YOU AGREE TO
|
||||
BE BOUND BY THIS AGREEMENT'S TERMS AND CONDITIONS. YOU FURTHER
|
||||
AGREE THAT, EXCEPT FOR WRITTEN SEPARATE AGREEMENTS BETWEEN ID AND
|
||||
YOU, THIS AGREEMENT IS A COMPLETE AND EXCLUSIVE STATEMENT OF THE
|
||||
RIGHTS AND LIABILITIES OF THE PARTIES. THIS AGREEMENT SUPERSEDES
|
||||
ALL PRIOR ORAL AGREEMENTS, PROPOSALS OR UNDERSTANDINGS, AND ANY
|
||||
OTHER COMMUNICATIONS BETWEEN ID AND YOU RELATING TO THE SUBJECT
|
||||
MATTER OF THIS AGREEMENT.
|
||||
|
||||
June 21, 1996
|
||||
|
||||
SHAREWARE VERSION: QUAKE LIMITED USE SOFTWARE LICENSE AGREEMENT
|
||||
(DWC:dw:3406.0024:DWC\doc:1163)
|
1901
NQ/data/TECHINFO.TXT
Normal file
1901
NQ/data/TECHINFO.TXT
Normal file
File diff suppressed because it is too large
Load Diff
177
NQ/docs/INSTALL
Normal file
177
NQ/docs/INSTALL
Normal file
@ -0,0 +1,177 @@
|
||||
INSTALL for Linux Quake
|
||||
-----------------------
|
||||
|
||||
Quake for Linux provides several different binary executables to support
|
||||
different hardware and drivers.
|
||||
|
||||
Included with Linux Quake are:
|
||||
- SVGALib Quake (squake)
|
||||
This is a software renderer Quake that runs at the text console in Linux.
|
||||
- GLQuake (glquake, glquake.glx and glquake.3dfxgl)
|
||||
This is a hardware renderer Quake that runs using hardware 3D
|
||||
acceleration.
|
||||
- X11 Quake (quake.x11)
|
||||
Software rendering in a window under X11.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Mount the Quake CD as one would usually mount a CDROM, this can be
|
||||
accomplished by using the command:
|
||||
|
||||
mount /dev/cdrom /mnt
|
||||
|
||||
As root. Once the CD is mounted, run the setup script on the CD as root.
|
||||
|
||||
$ su
|
||||
Password:
|
||||
# mount /dev/cdrom /mnt
|
||||
# /bin/sh /mnt/setup
|
||||
|
||||
The script will ask some questions about what options you want to install
|
||||
and automatically install the software into /usr/local/games/quake.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Requirements for SVGALib Quake:
|
||||
|
||||
- SVGALib 1.20 or later (/lib/libvga.so.1.2.10)
|
||||
- libc 5.2.18 or later (5.0.9 will not work, /lib/libc.so.5.2.18)
|
||||
or glibc (libc6) for the glibc version
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib supported mouse (usually if it works with X, it'll work with
|
||||
squake).
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Requirements for GLQuake:
|
||||
|
||||
- 3DFX based card for the GLQuake version, VooDoo, VooDoo Rush or VooDoo2
|
||||
at this writing. In order to use 3DFX hardware, you must have 3DFX's
|
||||
GLIDE drivers installed. RPMs for these drivers are available at:
|
||||
http://glide.xxedgexx.com/3DfxRPMS.html
|
||||
- For the glX version, an OpenGL implementation that includes hardware
|
||||
glX support.
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib compatible mouse for glquake or X11 for glquake.glx
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Requirements for X11 Quake:
|
||||
|
||||
- X11R5 later, only tested with XFree86, should work with most X Servers
|
||||
- libc 5.2.18 or later (5.0.9 will not work, /lib/libc.so.5.2.18)
|
||||
or glibc (libc6) for the glibc version
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib supported mouse (usually if it works with X, it'll work with
|
||||
squake).
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Additional notes for SVGALib Quake
|
||||
----------------------------------
|
||||
|
||||
SVGALib may not detect a 3-button mouse properly (it
|
||||
will only use two buttons). Check your /etc/vga/libvga.config
|
||||
and set it up for your mouse type.
|
||||
|
||||
Also, newer versions of SVGALib have an mouse_accel_type option. Most
|
||||
users will want to set this to "off" in /etc/vga/libvga.config.
|
||||
|
||||
Additional notes for GLQuake
|
||||
----------------------------
|
||||
|
||||
There are three different ways to execute GLQuake:
|
||||
|
||||
1. The binary "glquake" requires Mesa 3-D 2.5 or later installed and compiled
|
||||
with 3DFX support (fxMesa..() function interface). It also requires
|
||||
svgalib 1.3.0 or later for keyboard/mouse input. This binary is a console
|
||||
application. Mesa 3-D requires GLIDE to be installed.
|
||||
|
||||
2. The shell script "glquake.3dfxgl" runs the "glquake" binary after
|
||||
preloading the lib3dfxgl.so library. This is a port of 3DFX's Win32
|
||||
OpenGL MCD (Mini Client Driver) to Linux. It is faster than Mesa 3-D
|
||||
since it was written specifically with supporting GLQuake in mind.
|
||||
lib3dfxgl.so requires that GLIDE be installed.
|
||||
|
||||
3. The binary "glquake.glx" is linked against standard OpenGL libraries.
|
||||
It should run on many different hardward OpenGL implementations under
|
||||
Linux and X11. This binary is an X11 application and must be run under
|
||||
X11. It will work with Mesa 3-D as a standard glX based OpenGL
|
||||
applications. If the Mesa 3-D library is compiled with 3DFX support,
|
||||
you can have Mesa 3-D support 3DFX hardware under X11 by setting the
|
||||
enviroment variable "MESA_GLX_FX" to "fullscreen" for fullscreen mode
|
||||
and "window" for windowed mode, eg. "export MESA_GLX_FX=fullscreen" for sh
|
||||
or "setenv MESA_GLX_FX fullscreen" for csh.
|
||||
|
||||
For glquake, you must also have SVGALib or later installed (1.3.0 or later
|
||||
prefered). GLQuake uses SVGALib for mouse and keyboard handling.
|
||||
|
||||
If you have gpm and/or selection running, you will have to terminate them
|
||||
before running GLQuake since they will not give up the mouse when GLQuake
|
||||
attempts to run. You can kill gpm by typing 'killall gpm' as root.
|
||||
|
||||
You must run GLQuake as root or setuid root since it needs to access things
|
||||
such as sound, keyboard, mouse and the 3DFX video. Future versions may not
|
||||
require root permissions.
|
||||
|
||||
Additional notes for X11 Quake
|
||||
------------------------------
|
||||
|
||||
This is a windowed version that is generic for X11. It runs in a window
|
||||
and can be resized. You can specify a starting window size with:
|
||||
-width <width>
|
||||
-height <height>
|
||||
-winsize <width> <height>
|
||||
Default is 320x200. It works in 16bit modes, but it's slower (twice as many
|
||||
bytes to copy).
|
||||
|
||||
No other video modes are supported (just runs windowed). Mouse is read, but
|
||||
not "grabbed" by default. Go to the Options menu and turn on Use Mouse to grab
|
||||
the mouse and use it in the game (or type "_windowed_mouse 1" at the console).
|
||||
|
||||
Command Line Options for Linux Quake
|
||||
------------------------------------
|
||||
|
||||
-mem <mb>
|
||||
Specify memory in megabytes to allocate (default is 8MB, which should be fine
|
||||
for most needs).
|
||||
|
||||
-nostdout
|
||||
Don't do any output to stdout
|
||||
|
||||
-mdev <device> (SVGALib based versions only)
|
||||
Mouse device, default is /dev/mouse
|
||||
|
||||
-mrate <speed> (SVGALib based versions only)
|
||||
Mouse baud rate, default is 1200
|
||||
|
||||
-cddev <device>
|
||||
CD device, default is /dev/cdrom
|
||||
|
||||
-mode <modenum>
|
||||
Use indicated video mode
|
||||
|
||||
-nokdb
|
||||
Don't initialize keyboard
|
||||
|
||||
-sndbits <8 or 16>
|
||||
Set sound bit sample size. Default is 16 if supported.
|
||||
|
||||
-sndspeed <speed>
|
||||
Set sound speed. Usual values are 8000, 11025, 22051 and 44100.
|
||||
Default is 11025.
|
||||
|
||||
-sndmono
|
||||
Set mono sound
|
||||
|
||||
-sndstereo
|
||||
Set stereo sound (default if supported)
|
||||
|
177
NQ/docs/INSTALL.Quake
Normal file
177
NQ/docs/INSTALL.Quake
Normal file
@ -0,0 +1,177 @@
|
||||
INSTALL for Linux Quake
|
||||
-----------------------
|
||||
|
||||
Quake for Linux provides several different binary executables to support
|
||||
different hardware and drivers.
|
||||
|
||||
Included with Linux Quake are:
|
||||
- SVGALib Quake (squake)
|
||||
This is a software renderer Quake that runs at the text console in Linux.
|
||||
- GLQuake (glquake, glquake.glx and glquake.3dfxgl)
|
||||
This is a hardware renderer Quake that runs using hardware 3D
|
||||
acceleration.
|
||||
- X11 Quake (quake.x11)
|
||||
Software rendering in a window under X11.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Mount the Quake CD as one would usually mount a CDROM, this can be
|
||||
accomplished by using the command:
|
||||
|
||||
mount /dev/cdrom /mnt
|
||||
|
||||
As root. Once the CD is mounted, run the setup script on the CD as root.
|
||||
|
||||
$ su
|
||||
Password:
|
||||
# mount /dev/cdrom /mnt
|
||||
# /bin/sh /mnt/setup
|
||||
|
||||
The script will ask some questions about what options you want to install
|
||||
and automatically install the software into /usr/local/games/quake.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Requirements for SVGALib Quake:
|
||||
|
||||
- SVGALib 1.20 or later (/lib/libvga.so.1.2.10)
|
||||
- libc 5.2.18 or later (5.0.9 will not work, /lib/libc.so.5.2.18)
|
||||
or glibc (libc6) for the glibc version
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib supported mouse (usually if it works with X, it'll work with
|
||||
squake).
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Requirements for GLQuake:
|
||||
|
||||
- 3DFX based card for the GLQuake version, VooDoo, VooDoo Rush or VooDoo2
|
||||
at this writing. In order to use 3DFX hardware, you must have 3DFX's
|
||||
GLIDE drivers installed. RPMs for these drivers are available at:
|
||||
http://glide.xxedgexx.com/3DfxRPMS.html
|
||||
- For the glX version, an OpenGL implementation that includes hardware
|
||||
glX support.
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib compatible mouse for glquake or X11 for glquake.glx
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Requirements for X11 Quake:
|
||||
|
||||
- X11R5 later, only tested with XFree86, should work with most X Servers
|
||||
- libc 5.2.18 or later (5.0.9 will not work, /lib/libc.so.5.2.18)
|
||||
or glibc (libc6) for the glibc version
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib supported mouse (usually if it works with X, it'll work with
|
||||
squake).
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Additional notes for SVGALib Quake
|
||||
----------------------------------
|
||||
|
||||
SVGALib may not detect a 3-button mouse properly (it
|
||||
will only use two buttons). Check your /etc/vga/libvga.config
|
||||
and set it up for your mouse type.
|
||||
|
||||
Also, newer versions of SVGALib have an mouse_accel_type option. Most
|
||||
users will want to set this to "off" in /etc/vga/libvga.config.
|
||||
|
||||
Additional notes for GLQuake
|
||||
----------------------------
|
||||
|
||||
There are three different ways to execute GLQuake:
|
||||
|
||||
1. The binary "glquake" requires Mesa 3-D 2.5 or later installed and compiled
|
||||
with 3DFX support (fxMesa..() function interface). It also requires
|
||||
svgalib 1.3.0 or later for keyboard/mouse input. This binary is a console
|
||||
application. Mesa 3-D requires GLIDE to be installed.
|
||||
|
||||
2. The shell script "glquake.3dfxgl" runs the "glquake" binary after
|
||||
preloading the lib3dfxgl.so library. This is a port of 3DFX's Win32
|
||||
OpenGL MCD (Mini Client Driver) to Linux. It is faster than Mesa 3-D
|
||||
since it was written specifically with supporting GLQuake in mind.
|
||||
lib3dfxgl.so requires that GLIDE be installed.
|
||||
|
||||
3. The binary "glquake.glx" is linked against standard OpenGL libraries.
|
||||
It should run on many different hardward OpenGL implementations under
|
||||
Linux and X11. This binary is an X11 application and must be run under
|
||||
X11. It will work with Mesa 3-D as a standard glX based OpenGL
|
||||
applications. If the Mesa 3-D library is compiled with 3DFX support,
|
||||
you can have Mesa 3-D support 3DFX hardware under X11 by setting the
|
||||
enviroment variable "MESA_GLX_FX" to "fullscreen" for fullscreen mode
|
||||
and "window" for windowed mode, eg. "export MESA_GLX_FX=fullscreen" for sh
|
||||
or "setenv MESA_GLX_FX fullscreen" for csh.
|
||||
|
||||
For glquake, you must also have SVGALib or later installed (1.3.0 or later
|
||||
prefered). GLQuake uses SVGALib for mouse and keyboard handling.
|
||||
|
||||
If you have gpm and/or selection running, you will have to terminate them
|
||||
before running GLQuake since they will not give up the mouse when GLQuake
|
||||
attempts to run. You can kill gpm by typing 'killall gpm' as root.
|
||||
|
||||
You must run GLQuake as root or setuid root since it needs to access things
|
||||
such as sound, keyboard, mouse and the 3DFX video. Future versions may not
|
||||
require root permissions.
|
||||
|
||||
Additional notes for X11 Quake
|
||||
------------------------------
|
||||
|
||||
This is a windowed version that is generic for X11. It runs in a window
|
||||
and can be resized. You can specify a starting window size with:
|
||||
-width <width>
|
||||
-height <height>
|
||||
-winsize <width> <height>
|
||||
Default is 320x200. It works in 16bit modes, but it's slower (twice as many
|
||||
bytes to copy).
|
||||
|
||||
No other video modes are supported (just runs windowed). Mouse is read, but
|
||||
not "grabbed" by default. Go to the Options menu and turn on Use Mouse to grab
|
||||
the mouse and use it in the game (or type "_windowed_mouse 1" at the console).
|
||||
|
||||
Command Line Options for Linux Quake
|
||||
------------------------------------
|
||||
|
||||
-mem <mb>
|
||||
Specify memory in megabytes to allocate (default is 8MB, which should be fine
|
||||
for most needs).
|
||||
|
||||
-nostdout
|
||||
Don't do any output to stdout
|
||||
|
||||
-mdev <device> (SVGALib based versions only)
|
||||
Mouse device, default is /dev/mouse
|
||||
|
||||
-mrate <speed> (SVGALib based versions only)
|
||||
Mouse baud rate, default is 1200
|
||||
|
||||
-cddev <device>
|
||||
CD device, default is /dev/cdrom
|
||||
|
||||
-mode <modenum>
|
||||
Use indicated video mode
|
||||
|
||||
-nokdb
|
||||
Don't initialize keyboard
|
||||
|
||||
-sndbits <8 or 16>
|
||||
Set sound bit sample size. Default is 16 if supported.
|
||||
|
||||
-sndspeed <speed>
|
||||
Set sound speed. Usual values are 8000, 11025, 22051 and 44100.
|
||||
Default is 11025.
|
||||
|
||||
-sndmono
|
||||
Set mono sound
|
||||
|
||||
-sndstereo
|
||||
Set stereo sound (default if supported)
|
||||
|
157
NQ/docs/README
Normal file
157
NQ/docs/README
Normal file
@ -0,0 +1,157 @@
|
||||
README for Linux Quake
|
||||
----------------------
|
||||
|
||||
This README convers all versions of Quake for Linux:
|
||||
- SVGALib Quake (squake)
|
||||
- GLQuake (glquake, glquake.glx and glquake.3dfxgl)
|
||||
- X11 Quake (quake.x11)
|
||||
|
||||
Requirements for SVGALib Quake:
|
||||
|
||||
- SVGALib 1.20 or later (/lib/libvga.so.1.2.10)
|
||||
- libc 5.2.18 or later (5.0.9 will not work, /lib/libc.so.5.2.18)
|
||||
or glibc (libc6) for the glibc version
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib supported mouse (usually if it works with X, it'll work with
|
||||
squake).
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Requirements for GLQuake:
|
||||
|
||||
- 3DFX based card for the GLQuake version, VooDoo, VooDoo Rush or VooDoo2
|
||||
at this writing. In order to use 3DFX hardware, you must have 3DFX's
|
||||
GLIDE drivers installed. RPMs for these drivers are available at:
|
||||
http://glide.xxedgexx.com/3DfxRPMS.html
|
||||
- For the glX version, an OpenGL implementation that includes hardware
|
||||
glX support.
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib compatible mouse for glquake or X11 for glquake.glx
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Requirements for X11 Quake:
|
||||
|
||||
- X11R5 later, only tested with XFree86, should work with most X Servers
|
||||
- libc 5.2.18 or later (5.0.9 will not work, /lib/libc.so.5.2.18)
|
||||
or glibc (libc6) for the glibc version
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib supported mouse (usually if it works with X, it'll work with
|
||||
squake).
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Additional notes for SVGALib Quake
|
||||
----------------------------------
|
||||
|
||||
SVGALib may not detect a 3-button mouse properly (it
|
||||
will only use two buttons). Check your /etc/vga/libvga.config
|
||||
and set it up for your mouse type.
|
||||
|
||||
Additional notes for GLQuake
|
||||
----------------------------
|
||||
|
||||
There are three different ways to execute GLQuake:
|
||||
|
||||
1. The binary "glquake" requires Mesa 3-D 2.5 or later installed and compiled
|
||||
with 3DFX support (fxMesa..() function interface). It also requires
|
||||
svgalib 1.3.0 or later for keyboard/mouse input. This binary is a console
|
||||
application. Mesa 3-D requires GLIDE to be installed.
|
||||
|
||||
2. The shell script "glquake.3dfxgl" runs the "glquake" binary after
|
||||
preloading the lib3dfxgl.so library. This is a port of 3DFX's Win32
|
||||
OpenGL MCD (Mini Client Driver) to Linux. It is faster than Mesa 3-D
|
||||
since it was written specifically with supporting GLQuake in mind.
|
||||
lib3dfxgl.so requires that GLIDE be installed.
|
||||
|
||||
3. The binary "glquake.glx" is linked against standard OpenGL libraries.
|
||||
It should run on many different hardward OpenGL implementations under
|
||||
Linux and X11. This binary is an X11 application and must be run under
|
||||
X11. It will work with Mesa 3-D as a standard glX based OpenGL
|
||||
applications. If the Mesa 3-D library is compiled with 3DFX support,
|
||||
you can have Mesa 3-D support 3DFX hardware under X11 by setting the
|
||||
enviroment variable "MESA_GLX_FX" to "fullscreen" for fullscreen mode
|
||||
and "window" for windowed mode, eg. "export MESA_GLX_FX=fullscreen" for sh
|
||||
or "setenv MESA_GLX_FX fullscreen" for csh.
|
||||
|
||||
For glquake, you must also have SVGALib or later installed (1.3.0 or later
|
||||
prefered). GLQuake uses SVGALib for mouse and keyboard handling.
|
||||
|
||||
If you have gpm and/or selection running, you will have to terminate them
|
||||
before running GLQuake since they will not give up the mouse when GLQuake
|
||||
attempts to run. You can kill gpm by typing 'killall gpm' as root.
|
||||
|
||||
You must run GLQuake as root or setuid root since it needs to access things
|
||||
such as sound, keyboard, mouse and the 3DFX video. Future versions may not
|
||||
require root permissions.
|
||||
|
||||
Additional notes for X11 Quake
|
||||
------------------------------
|
||||
|
||||
This is a windowed version that is generic for X11. It runs in a window
|
||||
and can be resized. You can specify a starting window size with:
|
||||
-width <width>
|
||||
-height <height>
|
||||
-winsize <width> <height>
|
||||
Default is 320x200. It works in 16bit modes, but it's slower (twice as many
|
||||
bytes to copy).
|
||||
|
||||
No other video modes are supported (just runs windowed). Mouse is read, but
|
||||
not "grabbed" by default. Go to the Options menu and turn on Use Mouse to grab
|
||||
the mouse and use it in the game (or type "_windowed_mouse 1" at the console).
|
||||
|
||||
Command Line Options for Linux Quake
|
||||
------------------------------------
|
||||
|
||||
-mem <mb>
|
||||
Specify memory in megabytes to allocate (default is 8MB, which should be fine
|
||||
for most needs).
|
||||
|
||||
-nostdout
|
||||
Don't do any output to stdout
|
||||
|
||||
-mdev <device> (SVGALib based versions only)
|
||||
Mouse device, default is /dev/mouse
|
||||
|
||||
-mrate <speed> (SVGALib based versions only)
|
||||
Mouse baud rate, default is 1200
|
||||
|
||||
-cddev <device>
|
||||
CD device, default is /dev/cdrom
|
||||
|
||||
-mode <modenum>
|
||||
Use indicated video mode
|
||||
|
||||
-nokdb
|
||||
Don't initialize keyboard
|
||||
|
||||
-sndbits <8 or 16>
|
||||
Set sound bit sample size. Default is 16 if supported.
|
||||
|
||||
-sndspeed <speed>
|
||||
Set sound speed. Usual values are 8000, 11025, 22051 and 44100.
|
||||
Default is 11025.
|
||||
|
||||
-sndmono
|
||||
Set mono sound
|
||||
|
||||
-sndstereo
|
||||
Set stereo sound (default if supported)
|
||||
|
||||
End Notes
|
||||
---------
|
||||
|
||||
Linux Quake is *NOT* an officially supported product. Mail about it
|
||||
will be deleted. Do not email id about this product. If you are having
|
||||
technical difficultly, you can email me, but make sure you have the correct
|
||||
kernel, libc, svgalib and other software versions before you email me.
|
||||
|
||||
Dave 'Zoid' Kirsch
|
||||
zoid@idsoftware.com
|
||||
Official Quake Unix Port Administrator
|
107
NQ/docs/README.X11
Normal file
107
NQ/docs/README.X11
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
README for Linux SVGALib Quake
|
||||
------------------------------
|
||||
|
||||
Requirements:
|
||||
|
||||
- X11R5 later, only tested with XFree86, should work with most X Servers
|
||||
- libc 5.2.18 or later (5.0.9 will not work, /lib/libc.so.5.2.18)
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib supported mouse (usually if it works with X, it'll work with
|
||||
squake).
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
This is a windowed version that is generic for X11. It runs in a window
|
||||
and can be resized. You can specify a starting window size with:
|
||||
-width <width>
|
||||
-height <height>
|
||||
-winsize <width> <height>
|
||||
Default is 320x200. It works in 16bit modes, but it's slower (twice as many
|
||||
bytes to copy).
|
||||
|
||||
No other video modes are supported (just runs windowed). Mouse is read, but
|
||||
not "grabbed" by default. Go to the Options menu and turn on Use Mouse to grab
|
||||
the mouse and use it in the game. If you want to move the mouse out of
|
||||
QWCL, you have to turn Use Mouse off.
|
||||
|
||||
Full sound support is included. The default sound rate is 16-bit stereo,
|
||||
11KHz. You can change this in the options section below.
|
||||
|
||||
New Command Line Options for Linux SVGAlib Quake
|
||||
------------------------------------------------
|
||||
|
||||
-mem <mb>
|
||||
Specify memory in megabytes to allocate (default is 8MB, which should be fine
|
||||
for most needs).
|
||||
|
||||
-nostdout
|
||||
Don't do any output to stdout
|
||||
|
||||
-cddev <device>
|
||||
CD device, default is /dev/cdrom
|
||||
|
||||
-sndbits <8 or 16>
|
||||
Set sound bit sample size. Default is 16 if supported.
|
||||
|
||||
-sndspeed <speed>
|
||||
Set sound speed. Usual values are 8000, 11025, 22051 and 44100.
|
||||
Default is 11025.
|
||||
|
||||
-sndmono
|
||||
Set mono sound
|
||||
|
||||
-sndstereo
|
||||
Set stereo sound (default if supported)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Boot DOS (I know, but you need it to run the Quake install program) and
|
||||
install Quake from your Quake CD to a DOS parition.
|
||||
|
||||
Boot Linux and make a directory for Quake. Copy everything from the DOS Quake
|
||||
directory into it. i.e.:
|
||||
(cd /dos/quake; tar cf - .) | (cd ~/quake; tar xf -)
|
||||
|
||||
Quake for X11 does not need to be setuid root. Sound can fail if /dev/dsp is
|
||||
not mode 666.
|
||||
|
||||
Quake may segfault if it tries to initialize your sound card and their isn't
|
||||
one. Same with the CDROM. If it dies, try it with -nosound and/or
|
||||
-nocdaudio. If you have a sound card it died on and you know it is
|
||||
supported by USSLite (the driver that comes with the Linux kernel), let me
|
||||
know and I'll take a look at it.
|
||||
|
||||
It should work with SCSI CDROMs, but is untested.
|
||||
|
||||
Full TCP/IP network support is in, including listen and dedicated server
|
||||
modes.
|
||||
|
||||
All of the options described in TECHINFO.TXT and MANUAL.TXT from the Quake
|
||||
distribution will work, 'cept for stuff with vid modes and stuff.
|
||||
|
||||
End Notes
|
||||
---------
|
||||
|
||||
Linux Quake is *NOT* an officially supported product. Mail about it
|
||||
will be deleted. Do not email id about this product. If you are having
|
||||
technical difficultly, you can email me, but make sure you have the correct
|
||||
kernel, libc, svgalib and other software versions before you email me.
|
||||
|
||||
Dave 'Zoid' Kirsch
|
||||
zoid@idsoftware.com
|
||||
Official Quake Unix Port Administrator
|
||||
|
||||
Acks
|
||||
----
|
||||
|
||||
Greg Alexander <galexand@sietch.bloomington.in.us> for initial work in SVGALib
|
||||
support.
|
||||
Dave Taylor <ddt@crack.com> for basic Linux support.
|
||||
id Software for Quake and making me port it. :)
|
||||
|
||||
Lots of people on #linux, #quake for testing.
|
||||
|
162
NQ/docs/readme.glquake
Normal file
162
NQ/docs/readme.glquake
Normal file
@ -0,0 +1,162 @@
|
||||
Linux Glquake v0.98, Quake v1.09 release notes
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
For 3DFX based hardware, you must download and install Linux GLIDE from
|
||||
http://glide.xxedgexx.com/3DfxRPMS.html and install as per the
|
||||
instructions.
|
||||
|
||||
Running GLQuake
|
||||
---------------
|
||||
|
||||
There are three different ways to execute GLQuake:
|
||||
|
||||
1. The binary "glquake" requires Mesa 3-D 2.5 or later installed and compiled
|
||||
with 3DFX support (fxMesa..() function interface). It also requires
|
||||
svgalib 1.3.0 or later for keyboard/mouse input. This binary is a console
|
||||
application. Mesa 3-D requires GLIDE to be installed.
|
||||
|
||||
2. The shell script "glquake.3dfxgl" runs the "glquake" binary after
|
||||
preloading the lib3dfxgl.so library. This is a port of 3DFX's Win32
|
||||
OpenGL MCD (Mini Client Driver) to Linux. It is faster than Mesa 3-D
|
||||
since it was written specifically with supporting GLQuake in mind.
|
||||
lib3dfxgl.so requires that GLIDE be installed.
|
||||
|
||||
3. The binary "glquake.glx" is linked against standard OpenGL libraries.
|
||||
It should run on many different hardward OpenGL implementations under
|
||||
Linux and X11. This binary is an X11 application and must be run under
|
||||
X11. It will work with Mesa 3-D as a standard glX based OpenGL
|
||||
applications. If the Mesa 3-D library is compiled with 3DFX support,
|
||||
you can have Mesa 3-D support 3DFX hardware under X11 by setting the
|
||||
enviroment variable "MESA_GLX_FX" to "fullscreen" for fullscreen mode
|
||||
and "window" for windowed mode.
|
||||
|
||||
You must also have SVGALib 1.3.0 or later installed. GLQuake uses SVGALib
|
||||
for mouse and keyboard handling.
|
||||
|
||||
If you have gpm and/or selection running, you will have to terminate them
|
||||
before running GLQuake since they will not give up the mouse when GLQuake
|
||||
attempts to run. You can kill gpm by typing 'killall gpm' as root.
|
||||
|
||||
You must run GLQuake as root or setuid root since it needs to access things
|
||||
such as sound, keyboard, mouse and the 3DFX video. Future versions may not
|
||||
require root permissions.
|
||||
|
||||
resolution options
|
||||
------------------
|
||||
glquake -width 512 -height 384
|
||||
Tries to run glquake at the specified resolution.
|
||||
Only highend VooDoo cards support such high resolutions (most
|
||||
cards on the market right now do not). Another popular and supported mode
|
||||
is 512x384 (-width 512 -height 384) which can offer a faster speed than
|
||||
the default 640x480.
|
||||
|
||||
You can also specify the resolution of the console independant of the screen
|
||||
resolution.
|
||||
|
||||
glquake -conwidth 320
|
||||
This will specify a console resolution of 320 by 240 (the height is
|
||||
automatically determined by the default 4:3 aspect ratio, you can also
|
||||
specify the height directly with -conheight).
|
||||
|
||||
In higher resolution modes such as 800x600 and 1024x768, glquake will default
|
||||
to a 640x480 console, since the font becomes small enough at higher
|
||||
resolutions to become unreadable. If do you wish to have a higher resolution
|
||||
console and status bar, specify it as well, such as:
|
||||
glquake -width 800 -height 600 -conwidth 800
|
||||
|
||||
texture options
|
||||
---------------
|
||||
The amount of textures used in the game can have a large impact on performance.
|
||||
There are several options that let you trade off visual quality for better
|
||||
performance.
|
||||
|
||||
There is no way to flush already loaded textures, so it is best to change
|
||||
these options on the command line, or they will only take effect on some of
|
||||
the textures when you change levels.
|
||||
|
||||
OpenGL only allows textures to repeat on power of two boundaries (32, 64,
|
||||
128, etc), but software quake had a number of textures that repeated at 24
|
||||
or 96 pixel boundaries. These need to be either stretched out to the next
|
||||
higher size, or shrunk down to the next lower. By default, they are filtered
|
||||
down to the smaller size, but you can cause it to use the larger size if you
|
||||
really want by using:
|
||||
|
||||
glquake +gl_round_down 0
|
||||
This will generally run well on a normal 4 MB 3dfx card, but for other cards
|
||||
that have either worse texture management or slower texture swapping speeds,
|
||||
there are some additional settings that can drastically lower the amount of
|
||||
textures to be managed.
|
||||
|
||||
glquake +gl_picmip 1
|
||||
This causes all textures to have one half the dimensions they otherwise would.
|
||||
This makes them blurry, but very small. You can set this to 2 to make the
|
||||
textures one quarter the resolution on each axis for REALLY blurry textures.
|
||||
|
||||
glquake +gl_playermip 1
|
||||
This is similar to picmip, but is only used for other players in deathmatch.
|
||||
Each player in a deathmatch requires an individual skin texture, so this can
|
||||
be a serious problem for texture management. It wouldn't be unreasonable to
|
||||
set this to 2 or even 3 if you are playing competatively (and don't care if
|
||||
the other guys have smudged skins). If you change this during the game, it
|
||||
will take effect as soon as a player changes their skin colors.
|
||||
|
||||
run time options
|
||||
----------------
|
||||
At the console, you can set these values to effect drawing.
|
||||
|
||||
gl_texturemode GL_NEAREST
|
||||
Sets texture mapping to point sampled, which may be faster on some GL systems
|
||||
(not on 3dfx).
|
||||
|
||||
gl_texturemode GL_LINEAR_MIPMAP
|
||||
This is the default texture mode.
|
||||
|
||||
gl_texturemode GL_LINEAR_MIPMAP_LINEAR
|
||||
This is the highest quality texture mapping (trilinear), but only very high
|
||||
end hardware (intergraph intense 3D / realizm) supports it. Not that big of
|
||||
a deal, actually.
|
||||
|
||||
gl_finish 0
|
||||
This causes the game to not issue a glFinish() call each frame, which may make
|
||||
some hardware run faster. If this is cleared, the 3dfx will back up a number
|
||||
of frames and not be very playable.
|
||||
|
||||
gl_flashblend 0
|
||||
By default, glquake just draws a shaded ball around objects that are emiting
|
||||
light. Clearing this variable will cause it to properly relight the world
|
||||
like normal quake, but it can be a significant speed hit on some systems.
|
||||
|
||||
gl_ztrick 0
|
||||
Glquake uses a buffering method that avoids clearing the Z buffer, but some
|
||||
hardware platforms don't like it. If the status bar and console are flashing
|
||||
every other frame, clear this variable.
|
||||
|
||||
gl_keeptjunctions 0
|
||||
If you clear this, glquake will remove colinear vertexes when it reloads the
|
||||
level. This can give a few percent speedup, but it can leave a couple stray
|
||||
blinking pixels on the screen.
|
||||
|
||||
novelty features
|
||||
----------------
|
||||
These are some rendering tricks that were easy to do in glquake. They aren't
|
||||
very robust, but they are pretty cool to look at.
|
||||
|
||||
r_shadows 1
|
||||
This causes every object to cast a shadow.
|
||||
|
||||
r_wateralpha 0.7
|
||||
This sets the opacity of water textures, so you can see through it in properly
|
||||
processed maps. 0.3 is very faint, almost like fog. 1 is completely solid
|
||||
(the default). Unfortunately, the standard quake maps don't contain any
|
||||
visibility information for seeing past water surfaces, so you can't just play
|
||||
quake with this turned on. If you just want to see what it looks like, you
|
||||
can set "r_novis 1", but that will make things go very slow. When I get a
|
||||
chance, I will probably release some maps that have been processed properly
|
||||
for this.
|
||||
|
||||
r_mirroralpha 0.3
|
||||
This changes one particular texture (the stained glass texture in the EASY
|
||||
start hall) into a mirror. The value is the opacity of the mirror surface.
|
||||
|
127
NQ/docs/readme.squake
Normal file
127
NQ/docs/readme.squake
Normal file
@ -0,0 +1,127 @@
|
||||
|
||||
README for Linux SVGALib Quake
|
||||
------------------------------
|
||||
|
||||
Requirements:
|
||||
|
||||
- SVGALib 1.20 or later (/lib/libvga.so.1.2.10)
|
||||
- libc 5.2.18 or later (5.0.9 will not work, /lib/libc.so.5.2.18)
|
||||
- CD-ROM for CDAudio
|
||||
- Soundcard capable of mmap'd buffers. USSLite 3.5.4 was used to build squake
|
||||
with. Works fine on SoundBlaster 16 and Gravis Ultrasound MAX.
|
||||
- SVGALib supported mouse (usually if it works with X, it'll work with
|
||||
squake).
|
||||
- Kernel 2.0.24 or later
|
||||
- untested with 2.1 kernels, your mileage may vary
|
||||
|
||||
Here's the release you've been waiting for. Linux squake supports
|
||||
320x200x256, the various modeX modes (320x400, 360x400, etc) as well as high
|
||||
res modes if your card is supported by SVGALib. Use the Quake console command
|
||||
vid_describemodes to list supported modes and the command vid_mode <number> to
|
||||
change modes.
|
||||
|
||||
Full sound support is included. The default sound rate is 16-bit stereo,
|
||||
11KHz. You can change this in the options section below.
|
||||
|
||||
Mouse works great, but SVGALib may not detect a 3-button mouse properly (it
|
||||
will only use two buttons). Check your /etc/libvga.config (or
|
||||
/etc/vga/libvga.config for SlackWare users).
|
||||
|
||||
**Version 1.1 fixes some crash bugs with the mission packs.
|
||||
|
||||
New Command Line Options for Linux SVGAlib Quake
|
||||
------------------------------------------------
|
||||
|
||||
-mem <mb>
|
||||
Specify memory in megabytes to allocate (default is 8MB, which should be fine
|
||||
for most needs).
|
||||
|
||||
-nostdout
|
||||
Don't do any output to stdout
|
||||
|
||||
-mdev <device>
|
||||
Mouse device, default is /dev/mouse
|
||||
|
||||
-mrate <speed>
|
||||
Mouse baud rate, default is 1200
|
||||
|
||||
-cddev <device>
|
||||
CD device, default is /dev/cdrom
|
||||
|
||||
-mode <modenum>
|
||||
Use indicated video mode
|
||||
|
||||
-nokdb
|
||||
Don't initialize keyboard
|
||||
|
||||
-sndbits <8 or 16>
|
||||
Set sound bit sample size. Default is 16 if supported.
|
||||
|
||||
-sndspeed <speed>
|
||||
Set sound speed. Usual values are 8000, 11025, 22051 and 44100.
|
||||
Default is 11025.
|
||||
|
||||
-sndmono
|
||||
Set mono sound
|
||||
|
||||
-sndstereo
|
||||
Set stereo sound (default if supported)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Boot DOS (I know, but you need it to run the Quake install program) and
|
||||
install Quake from your Quake CD to a DOS parition.
|
||||
|
||||
Boot Linux and make a directory for Quake. Copy everything from the DOS Quake
|
||||
directory into it. i.e.:
|
||||
(cd /dos/quake; tar cf - .) | (cd ~/quake; tar xf -)
|
||||
|
||||
Place squake into your Quake directory. You must make it setuid root (since
|
||||
Quake access stuff like direct video writes, the raw keyboard mode, CD, etc).
|
||||
Quake will setuid back to the normal user as soon as it opens these files.
|
||||
Make Quake suid root as follows:
|
||||
chown root squake
|
||||
chmod 4755 squake
|
||||
|
||||
Run squake. I don't recommend running it as root, since all the saved
|
||||
config.cfg files will be then owned as root. Use your normal account, unless
|
||||
you do everything as root, then your mileage will vary.
|
||||
|
||||
squake may segfault if it tries to initialize your sound card and their isn't
|
||||
one. Same with the CDROM. If it dies, try it with -nosound and/or
|
||||
-nocdaudio. If you have a sound card it died on and you know it is
|
||||
supported by USSLite (the driver that comes with the Linux kernel), let me
|
||||
know and I'll take a look at it.
|
||||
|
||||
It should work with SCSI CDROMs, but is untested.
|
||||
|
||||
Full TCP/IP network support is in, including listen and dedicated server
|
||||
modes. squake makes a nice dedicated server as you don't need the X11
|
||||
libraries kicking around.
|
||||
|
||||
All of the options described in TECHINFO.TXT and MANUAL.TXT from the Quake
|
||||
distribution will work, 'cept for stuff with vid modes and stuff.
|
||||
|
||||
End Notes
|
||||
---------
|
||||
|
||||
Linux SVGALib Quake is *NOT* an officially supported product. Mail about it
|
||||
will be deleted. Do not email id about this product. If you are having
|
||||
technical difficultly, you can email me, but make sure you have the correct
|
||||
kernel, libc, svgalib and other software versions before you email me.
|
||||
|
||||
Dave 'Zoid' Kirsch
|
||||
zoid@threewave.com
|
||||
Official Quake Unix Port Administrator
|
||||
|
||||
Acks
|
||||
----
|
||||
|
||||
Greg Alexander <galexand@sietch.bloomington.in.us> for initial work in SVGALib
|
||||
support.
|
||||
Dave Taylor <ddt@crack.com> for basic Linux support.
|
||||
id Software for Quake and making me port it. :)
|
||||
|
||||
Lots of people on #linux, #quake for testing.
|
||||
|
77
NQ/dosasm.S
Normal file
77
NQ/dosasm.S
Normal file
@ -0,0 +1,77 @@
|
||||
#include "asm_i386.h"
|
||||
|
||||
.data
|
||||
fpenv: .long 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
.text
|
||||
.globl C(StartMSRInterval)
|
||||
C(StartMSRInterval):
|
||||
movl $0x11,%ecx // read the CESR
|
||||
.byte 0x0F
|
||||
.byte 0x32 // RDMSR
|
||||
|
||||
andl $0xFE3FFE3F,%eax // stop both counters
|
||||
.byte 0x0F
|
||||
.byte 0x30 // WRMSR
|
||||
|
||||
movl 4(%esp),%eax // point counter 0 to desired event, with counters
|
||||
andl $0x3F,%eax // still stopped
|
||||
movl $0x11,%ecx
|
||||
.byte 0x0F
|
||||
.byte 0x30 // WRMSR
|
||||
|
||||
movl $0x12,%ecx // set counter 0 to the value 0
|
||||
subl %eax,%eax
|
||||
subl %edx,%edx
|
||||
.byte 0x0F
|
||||
.byte 0x30 // WRMSR
|
||||
|
||||
movl 4(%esp),%eax // restart counter 0 with selected event
|
||||
andl $0x3F,%eax
|
||||
subl %edx,%edx
|
||||
orl $0xC0,%eax
|
||||
movl $0x11,%ecx // control and event select
|
||||
.byte 0x0F
|
||||
.byte 0x30 // WRMSR
|
||||
|
||||
ret
|
||||
|
||||
.globl C(EndMSRInterval)
|
||||
C(EndMSRInterval):
|
||||
movl $0x12,%ecx // counter 0
|
||||
.byte 0x0F
|
||||
.byte 0x32 // RDMSR
|
||||
|
||||
ret // lower 32 bits of count in %eax
|
||||
|
||||
#if 0
|
||||
.data
|
||||
Lxxx: .long 0
|
||||
|
||||
.text
|
||||
|
||||
.globl C(setstackcheck)
|
||||
C(setstackcheck):
|
||||
|
||||
movl %esp,%eax
|
||||
subl $0x38000,%eax
|
||||
movl $0x5A5A5A5A,(%eax)
|
||||
movl %eax,Lxxx
|
||||
|
||||
ret
|
||||
|
||||
|
||||
.globl C(dostackcheck)
|
||||
C(dostackcheck):
|
||||
|
||||
movl Lxxx,%edx
|
||||
movl $0,%eax
|
||||
|
||||
cmpl $0x5A5A5A5A,(%edx)
|
||||
jz qqq
|
||||
incl %eax
|
||||
qqq:
|
||||
|
||||
ret
|
||||
#endif
|
||||
|
99
NQ/dosisms.h
Normal file
99
NQ/dosisms.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DOSISMS_H
|
||||
#define DOSISMS_H
|
||||
|
||||
//
|
||||
// dosisms.h: I'd call it dos.h, but the name's taken
|
||||
//
|
||||
|
||||
int dos_lockmem(void *addr, int size);
|
||||
int dos_unlockmem(void *addr, int size);
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
unsigned long edi;
|
||||
unsigned long esi;
|
||||
unsigned long ebp;
|
||||
unsigned long res;
|
||||
unsigned long ebx;
|
||||
unsigned long edx;
|
||||
unsigned long ecx;
|
||||
unsigned long eax;
|
||||
} d;
|
||||
struct {
|
||||
unsigned short di, di_hi;
|
||||
unsigned short si, si_hi;
|
||||
unsigned short bp, bp_hi;
|
||||
unsigned short res, res_hi;
|
||||
unsigned short bx, bx_hi;
|
||||
unsigned short dx, dx_hi;
|
||||
unsigned short cx, cx_hi;
|
||||
unsigned short ax, ax_hi;
|
||||
unsigned short flags;
|
||||
unsigned short es;
|
||||
unsigned short ds;
|
||||
unsigned short fs;
|
||||
unsigned short gs;
|
||||
unsigned short ip;
|
||||
unsigned short cs;
|
||||
unsigned short sp;
|
||||
unsigned short ss;
|
||||
} x;
|
||||
struct {
|
||||
unsigned char edi[4];
|
||||
unsigned char esi[4];
|
||||
unsigned char ebp[4];
|
||||
unsigned char res[4];
|
||||
unsigned char bl, bh, ebx_b2, ebx_b3;
|
||||
unsigned char dl, dh, edx_b2, edx_b3;
|
||||
unsigned char cl, ch, ecx_b2, ecx_b3;
|
||||
unsigned char al, ah, eax_b2, eax_b3;
|
||||
} h;
|
||||
} regs_t;
|
||||
|
||||
unsigned int ptr2real(void *ptr);
|
||||
void *real2ptr(unsigned int real);
|
||||
void *far2ptr(unsigned int farptr);
|
||||
unsigned int ptr2far(void *ptr);
|
||||
|
||||
int dos_inportb(int port);
|
||||
int dos_inportw(int port);
|
||||
void dos_outportb(int port, int val);
|
||||
void dos_outportw(int port, int val);
|
||||
|
||||
void dos_irqenable(void);
|
||||
void dos_irqdisable(void);
|
||||
void dos_registerintr(int intr, void (*handler) (void));
|
||||
void dos_restoreintr(int intr);
|
||||
|
||||
int dos_int86(int vec);
|
||||
|
||||
void *dos_getmemory(int size);
|
||||
void dos_freememory(void *ptr);
|
||||
|
||||
void dos_usleep(int usecs);
|
||||
|
||||
int dos_getheapsize(void);
|
||||
|
||||
extern regs_t regs;
|
||||
|
||||
#endif /* DOSISMS_H */
|
1075
NQ/gas2masm/gas2masm.c
Normal file
1075
NQ/gas2masm/gas2masm.c
Normal file
File diff suppressed because it is too large
Load Diff
418
NQ/gl_model.h
Normal file
418
NQ/gl_model.h
Normal file
@ -0,0 +1,418 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GL_MODEL_H
|
||||
#define GL_MODEL_H
|
||||
|
||||
#include "modelgen.h"
|
||||
#include "spritegn.h"
|
||||
#include "bspfile.h"
|
||||
#include "render.h"
|
||||
#include "zone.h"
|
||||
|
||||
/*
|
||||
|
||||
d*_t structures are on-disk representations
|
||||
m*_t structures are in-memory
|
||||
|
||||
*/
|
||||
|
||||
// entity effects
|
||||
|
||||
#define EF_BRIGHTFIELD 1
|
||||
#define EF_MUZZLEFLASH 2
|
||||
#define EF_BRIGHTLIGHT 4
|
||||
#define EF_DIMLIGHT 8
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
BRUSH MODELS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// in memory representation
|
||||
//
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct {
|
||||
vec3_t position;
|
||||
} mvertex_t;
|
||||
|
||||
#define SIDE_FRONT 0
|
||||
#define SIDE_BACK 1
|
||||
#define SIDE_ON 2
|
||||
|
||||
|
||||
// plane_t structure
|
||||
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
||||
typedef struct mplane_s {
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
byte type; // for texture axis selection and fast side tests
|
||||
byte signbits; // signx + signy<<1 + signz<<1
|
||||
byte pad[2];
|
||||
} mplane_t;
|
||||
|
||||
typedef struct texture_s {
|
||||
char name[16];
|
||||
unsigned width, height;
|
||||
int gl_texturenum;
|
||||
struct msurface_s *texturechain; // for gl_texsort drawing
|
||||
int anim_total; // total tenths in sequence ( 0 = no)
|
||||
int anim_min, anim_max; // time for this frame min <=time< max
|
||||
struct texture_s *anim_next; // in the animation sequence
|
||||
struct texture_s *alternate_anims; // bmodels in frmae 1 use these
|
||||
unsigned offsets[MIPLEVELS]; // four mip maps stored
|
||||
} texture_t;
|
||||
|
||||
|
||||
#define SURF_PLANEBACK 2
|
||||
#define SURF_DRAWSKY 4
|
||||
#define SURF_DRAWSPRITE 8
|
||||
#define SURF_DRAWTURB 0x10
|
||||
#define SURF_DRAWTILED 0x20
|
||||
#define SURF_DRAWBACKGROUND 0x40
|
||||
#define SURF_UNDERWATER 0x80
|
||||
#define SURF_DONTWARP 0x100
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct {
|
||||
unsigned short v[2];
|
||||
unsigned int cachededgeoffset;
|
||||
} medge_t;
|
||||
|
||||
typedef struct {
|
||||
float vecs[2][4];
|
||||
float mipadjust;
|
||||
texture_t *texture;
|
||||
int flags;
|
||||
} mtexinfo_t;
|
||||
|
||||
#define VERTEXSIZE 7
|
||||
|
||||
typedef struct glpoly_s {
|
||||
struct glpoly_s *next;
|
||||
struct glpoly_s *chain;
|
||||
int numverts;
|
||||
int flags; // for SURF_UNDERWATER
|
||||
float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2)
|
||||
} glpoly_t;
|
||||
|
||||
typedef struct msurface_s {
|
||||
int visframe; // should be drawn when node is crossed
|
||||
|
||||
mplane_t *plane;
|
||||
int flags;
|
||||
|
||||
int firstedge; // look up in model->surfedges[], negative numbers
|
||||
int numedges; // are backwards edges
|
||||
|
||||
short texturemins[2];
|
||||
short extents[2];
|
||||
|
||||
int light_s, light_t; // gl lightmap coordinates
|
||||
|
||||
glpoly_t *polys; // multiple if warped
|
||||
struct msurface_s *texturechain;
|
||||
|
||||
mtexinfo_t *texinfo;
|
||||
|
||||
// lighting info
|
||||
int dlightframe;
|
||||
unsigned dlightbits;
|
||||
|
||||
int lightmaptexturenum;
|
||||
byte styles[MAXLIGHTMAPS];
|
||||
int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap
|
||||
qboolean cached_dlight; // true if dynamic light in cache
|
||||
byte *samples; // [numstyles*surfsize]
|
||||
} msurface_t;
|
||||
|
||||
typedef struct mnode_s {
|
||||
// common with leaf
|
||||
int contents; // 0, to differentiate from leafs
|
||||
int visframe; // node needs to be traversed if current
|
||||
|
||||
float minmaxs[6]; // for bounding box culling
|
||||
|
||||
struct mnode_s *parent;
|
||||
|
||||
// node specific
|
||||
mplane_t *plane;
|
||||
struct mnode_s *children[2];
|
||||
|
||||
unsigned short firstsurface;
|
||||
unsigned short numsurfaces;
|
||||
} mnode_t;
|
||||
|
||||
|
||||
|
||||
typedef struct mleaf_s {
|
||||
// common with node
|
||||
int contents; // wil be a negative contents number
|
||||
int visframe; // node needs to be traversed if current
|
||||
|
||||
float minmaxs[6]; // for bounding box culling
|
||||
|
||||
struct mnode_s *parent;
|
||||
|
||||
// leaf specific
|
||||
byte *compressed_vis;
|
||||
efrag_t *efrags;
|
||||
|
||||
msurface_t **firstmarksurface;
|
||||
int nummarksurfaces;
|
||||
int key; // BSP sequence number for leaf's contents
|
||||
byte ambient_sound_level[NUM_AMBIENTS];
|
||||
} mleaf_t;
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
||||
typedef struct {
|
||||
dclipnode_t *clipnodes;
|
||||
mplane_t *planes;
|
||||
int firstclipnode;
|
||||
int lastclipnode;
|
||||
vec3_t clip_mins;
|
||||
vec3_t clip_maxs;
|
||||
} hull_t;
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
SPRITE MODELS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
// FIXME: shorten these?
|
||||
typedef struct mspriteframe_s {
|
||||
int width;
|
||||
int height;
|
||||
float up, down, left, right;
|
||||
int gl_texturenum;
|
||||
} mspriteframe_t;
|
||||
|
||||
typedef struct {
|
||||
int numframes;
|
||||
float *intervals;
|
||||
mspriteframe_t *frames[1];
|
||||
} mspritegroup_t;
|
||||
|
||||
typedef struct {
|
||||
spriteframetype_t type;
|
||||
mspriteframe_t *frameptr;
|
||||
} mspriteframedesc_t;
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
int maxwidth;
|
||||
int maxheight;
|
||||
int numframes;
|
||||
float beamlength; // remove?
|
||||
void *cachespot; // remove?
|
||||
mspriteframedesc_t frames[1];
|
||||
} msprite_t;
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
ALIAS MODELS
|
||||
|
||||
Alias models are position independent, so the cache manager can move them.
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int firstpose;
|
||||
int numposes;
|
||||
float interval;
|
||||
trivertx_t bboxmin;
|
||||
trivertx_t bboxmax;
|
||||
int frame;
|
||||
char name[16];
|
||||
} maliasframedesc_t;
|
||||
|
||||
typedef struct {
|
||||
trivertx_t bboxmin;
|
||||
trivertx_t bboxmax;
|
||||
int frame;
|
||||
} maliasgroupframedesc_t;
|
||||
|
||||
typedef struct {
|
||||
int numframes;
|
||||
int intervals;
|
||||
maliasgroupframedesc_t frames[1];
|
||||
} maliasgroup_t;
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct mtriangle_s {
|
||||
int facesfront;
|
||||
int vertindex[3];
|
||||
} mtriangle_t;
|
||||
|
||||
|
||||
#define MAX_SKINS 32
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
vec3_t scale;
|
||||
vec3_t scale_origin;
|
||||
float boundingradius;
|
||||
vec3_t eyeposition;
|
||||
int numskins;
|
||||
int skinwidth;
|
||||
int skinheight;
|
||||
int numverts;
|
||||
int numtris;
|
||||
int numframes;
|
||||
synctype_t synctype;
|
||||
int flags;
|
||||
float size;
|
||||
|
||||
int numposes;
|
||||
int poseverts;
|
||||
int posedata; // numposes*poseverts trivert_t
|
||||
int commands; // gl command list with embedded s/t
|
||||
int gl_texturenum[MAX_SKINS][4];
|
||||
int texels[MAX_SKINS]; // only for player skins
|
||||
maliasframedesc_t frames[1]; // variable sized
|
||||
} aliashdr_t;
|
||||
|
||||
#define MAXALIASVERTS 2048
|
||||
#define MAXALIASFRAMES 512
|
||||
#define MAXALIASTRIS 4096
|
||||
extern aliashdr_t *pheader;
|
||||
extern stvert_t stverts[MAXALIASVERTS];
|
||||
extern mtriangle_t triangles[MAXALIASTRIS];
|
||||
extern trivertx_t *poseverts[MAXALIASFRAMES];
|
||||
|
||||
//===================================================================
|
||||
|
||||
//
|
||||
// Whole model
|
||||
//
|
||||
|
||||
typedef enum { mod_brush, mod_sprite, mod_alias } modtype_t;
|
||||
|
||||
#define EF_ROCKET 1 // leave a trail
|
||||
#define EF_GRENADE 2 // leave a trail
|
||||
#define EF_GIB 4 // leave a trail
|
||||
#define EF_ROTATE 8 // rotate (bonus items)
|
||||
#define EF_TRACER 16 // green split trail
|
||||
#define EF_ZOMGIB 32 // small blood trail
|
||||
#define EF_TRACER2 64 // orange split trail + rotate
|
||||
#define EF_TRACER3 128 // purple trail
|
||||
|
||||
typedef struct model_s {
|
||||
char name[MAX_QPATH];
|
||||
qboolean needload; // bmodels and sprites don't cache normally
|
||||
|
||||
modtype_t type;
|
||||
int numframes;
|
||||
synctype_t synctype;
|
||||
|
||||
int flags;
|
||||
|
||||
//
|
||||
// volume occupied by the model graphics
|
||||
//
|
||||
vec3_t mins, maxs;
|
||||
float radius;
|
||||
|
||||
//
|
||||
// solid volume for clipping
|
||||
//
|
||||
qboolean clipbox;
|
||||
vec3_t clipmins, clipmaxs;
|
||||
|
||||
//
|
||||
// brush model
|
||||
//
|
||||
int firstmodelsurface, nummodelsurfaces;
|
||||
|
||||
int numsubmodels;
|
||||
dmodel_t *submodels;
|
||||
|
||||
int numplanes;
|
||||
mplane_t *planes;
|
||||
|
||||
int numleafs; // number of visible leafs, not counting 0
|
||||
mleaf_t *leafs;
|
||||
|
||||
int numvertexes;
|
||||
mvertex_t *vertexes;
|
||||
|
||||
int numedges;
|
||||
medge_t *edges;
|
||||
|
||||
int numnodes;
|
||||
mnode_t *nodes;
|
||||
|
||||
int numtexinfo;
|
||||
mtexinfo_t *texinfo;
|
||||
|
||||
int numsurfaces;
|
||||
msurface_t *surfaces;
|
||||
|
||||
int numsurfedges;
|
||||
int *surfedges;
|
||||
|
||||
int numclipnodes;
|
||||
dclipnode_t *clipnodes;
|
||||
|
||||
int nummarksurfaces;
|
||||
msurface_t **marksurfaces;
|
||||
|
||||
hull_t hulls[MAX_MAP_HULLS];
|
||||
|
||||
int numtextures;
|
||||
texture_t **textures;
|
||||
|
||||
byte *visdata;
|
||||
byte *lightdata;
|
||||
char *entities;
|
||||
|
||||
//
|
||||
// additional model data
|
||||
//
|
||||
cache_user_t cache; // only access through Mod_Extradata
|
||||
|
||||
} model_t;
|
||||
|
||||
//============================================================================
|
||||
|
||||
void Mod_Init(void);
|
||||
void Mod_ClearAll(void);
|
||||
model_t *Mod_ForName(char *name, qboolean crash);
|
||||
void *Mod_Extradata(model_t *mod); // handles caching
|
||||
void Mod_TouchModel(char *name);
|
||||
void Mod_Print(void);
|
||||
|
||||
mleaf_t *Mod_PointInLeaf(float *p, model_t *model);
|
||||
byte *Mod_LeafPVS(mleaf_t *leaf, model_t *model);
|
||||
|
||||
// FIXME - surely this doesn't belong here?
|
||||
texture_t *R_TextureAnimation(texture_t *base);
|
||||
|
||||
#endif /* GL_MODEL_H */
|
1182
NQ/gl_rmain.c
Normal file
1182
NQ/gl_rmain.c
Normal file
File diff suppressed because it is too large
Load Diff
471
NQ/gl_rmisc.c
Normal file
471
NQ/gl_rmisc.c
Normal file
@ -0,0 +1,471 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_misc.c
|
||||
|
||||
#include "cmd.h"
|
||||
#include "console.h"
|
||||
#include "glquake.h"
|
||||
#include "protocol.h"
|
||||
#include "quakedef.h"
|
||||
#include "sys.h"
|
||||
|
||||
// FIXME - should only be needed in r_part.c or here, not both.
|
||||
int particletexture;
|
||||
|
||||
/*
|
||||
==================
|
||||
R_InitTextures
|
||||
==================
|
||||
*/
|
||||
void
|
||||
R_InitTextures(void)
|
||||
{
|
||||
int x, y, m;
|
||||
byte *dest;
|
||||
|
||||
// create a simple checkerboard texture for the default
|
||||
r_notexture_mip =
|
||||
Hunk_AllocName(sizeof(texture_t) + 16 * 16 + 8 * 8 + 4 * 4 + 2 * 2,
|
||||
"notexture");
|
||||
|
||||
r_notexture_mip->width = r_notexture_mip->height = 16;
|
||||
r_notexture_mip->offsets[0] = sizeof(texture_t);
|
||||
r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16 * 16;
|
||||
r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8 * 8;
|
||||
r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4 * 4;
|
||||
|
||||
for (m = 0; m < 4; m++) {
|
||||
dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
|
||||
for (y = 0; y < (16 >> m); y++) {
|
||||
for (x = 0; x < (16 >> m); x++) {
|
||||
if ((y < (8 >> m)) ^ (x < (8 >> m)))
|
||||
*dest++ = 0;
|
||||
else
|
||||
*dest++ = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static byte dottexture[8][8] = {
|
||||
{0, 1, 1, 0, 0, 0, 0, 0},
|
||||
{1, 1, 1, 1, 0, 0, 0, 0},
|
||||
{1, 1, 1, 1, 0, 0, 0, 0},
|
||||
{0, 1, 1, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
static void
|
||||
R_InitParticleTexture(void)
|
||||
{
|
||||
int x, y;
|
||||
byte data[8][8][4];
|
||||
|
||||
//
|
||||
// particle texture
|
||||
//
|
||||
particletexture = texture_extension_number++;
|
||||
GL_Bind(particletexture);
|
||||
|
||||
for (x = 0; x < 8; x++) {
|
||||
for (y = 0; y < 8; y++) {
|
||||
data[y][x][0] = 255;
|
||||
data[y][x][1] = 255;
|
||||
data[y][x][2] = 255;
|
||||
data[y][x][3] = dottexture[x][y] * 255;
|
||||
}
|
||||
}
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, data);
|
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_Envmap_f
|
||||
|
||||
Grab six views for environment mapping tests
|
||||
===============
|
||||
*/
|
||||
static void
|
||||
R_Envmap_f(void)
|
||||
{
|
||||
byte buffer[256 * 256 * 4];
|
||||
|
||||
glDrawBuffer(GL_FRONT);
|
||||
glReadBuffer(GL_FRONT);
|
||||
envmap = true;
|
||||
|
||||
r_refdef.vrect.x = 0;
|
||||
r_refdef.vrect.y = 0;
|
||||
r_refdef.vrect.width = 256;
|
||||
r_refdef.vrect.height = 256;
|
||||
|
||||
r_refdef.viewangles[0] = 0;
|
||||
r_refdef.viewangles[1] = 0;
|
||||
r_refdef.viewangles[2] = 0;
|
||||
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
||||
R_RenderView();
|
||||
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
COM_WriteFile("env0.rgb", buffer, sizeof(buffer));
|
||||
|
||||
r_refdef.viewangles[1] = 90;
|
||||
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
||||
R_RenderView();
|
||||
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
COM_WriteFile("env1.rgb", buffer, sizeof(buffer));
|
||||
|
||||
r_refdef.viewangles[1] = 180;
|
||||
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
||||
R_RenderView();
|
||||
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
COM_WriteFile("env2.rgb", buffer, sizeof(buffer));
|
||||
|
||||
r_refdef.viewangles[1] = 270;
|
||||
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
||||
R_RenderView();
|
||||
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
COM_WriteFile("env3.rgb", buffer, sizeof(buffer));
|
||||
|
||||
r_refdef.viewangles[0] = -90;
|
||||
r_refdef.viewangles[1] = 0;
|
||||
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
||||
R_RenderView();
|
||||
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
COM_WriteFile("env4.rgb", buffer, sizeof(buffer));
|
||||
|
||||
r_refdef.viewangles[0] = 90;
|
||||
r_refdef.viewangles[1] = 0;
|
||||
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
||||
R_RenderView();
|
||||
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
COM_WriteFile("env5.rgb", buffer, sizeof(buffer));
|
||||
|
||||
envmap = false;
|
||||
glDrawBuffer(GL_BACK);
|
||||
glReadBuffer(GL_BACK);
|
||||
GL_EndRendering();
|
||||
}
|
||||
|
||||
// FIXME - locate somewhere else?
|
||||
cvar_t r_lockpvs = { "r_lockpvs", "0" };
|
||||
cvar_t r_lockfrustum = { "r_lockfrustum", "0" };
|
||||
cvar_t r_drawflat = { "r_drawflat", "0" };
|
||||
|
||||
/*
|
||||
===============
|
||||
R_Init
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_Init(void)
|
||||
{
|
||||
Cmd_AddCommand("envmap", R_Envmap_f);
|
||||
Cmd_AddCommand("pointfile", R_ReadPointFile_f);
|
||||
Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
|
||||
|
||||
Cvar_RegisterVariable(&r_speeds);
|
||||
Cvar_RegisterVariable(&r_fullbright);
|
||||
Cvar_RegisterVariable(&r_drawentities);
|
||||
Cvar_RegisterVariable(&r_drawviewmodel);
|
||||
Cvar_RegisterVariable(&r_drawflat);
|
||||
|
||||
Cvar_RegisterVariable(&r_lockpvs);
|
||||
Cvar_RegisterVariable(&r_lockfrustum);
|
||||
|
||||
Cvar_RegisterVariable(&r_norefresh);
|
||||
Cvar_RegisterVariable(&r_lightmap);
|
||||
Cvar_RegisterVariable(&r_shadows);
|
||||
Cvar_RegisterVariable(&r_mirroralpha);
|
||||
Cvar_RegisterVariable(&r_wateralpha);
|
||||
Cvar_RegisterVariable(&r_dynamic);
|
||||
Cvar_RegisterVariable(&r_novis);
|
||||
Cvar_RegisterVariable(&r_waterwarp);
|
||||
|
||||
Cvar_RegisterVariable(&gl_finish);
|
||||
Cvar_RegisterVariable(&gl_clear);
|
||||
Cvar_RegisterVariable(&gl_texsort);
|
||||
|
||||
Cvar_RegisterVariable(&_gl_lightmap_sort);
|
||||
Cvar_RegisterVariable(&_gl_sky_mtex);
|
||||
Cvar_RegisterVariable(&_gl_drawhull);
|
||||
|
||||
Cvar_RegisterVariable(&gl_cull);
|
||||
Cvar_RegisterVariable(&gl_smoothmodels);
|
||||
Cvar_RegisterVariable(&gl_affinemodels);
|
||||
Cvar_RegisterVariable(&gl_polyblend);
|
||||
Cvar_RegisterVariable(&gl_flashblend);
|
||||
Cvar_RegisterVariable(&gl_playermip);
|
||||
Cvar_RegisterVariable(&gl_nocolors);
|
||||
|
||||
Cvar_RegisterVariable(&gl_keeptjunctions);
|
||||
Cvar_RegisterVariable(&gl_reporttjunctions);
|
||||
|
||||
Cvar_RegisterVariable(&gl_doubleeyes);
|
||||
|
||||
if (gl_mtexable)
|
||||
Cvar_SetValue("gl_texsort", 0.0);
|
||||
|
||||
R_InitBubble();
|
||||
|
||||
R_InitParticles();
|
||||
R_InitParticleTexture();
|
||||
|
||||
playertextures = texture_extension_number;
|
||||
texture_extension_number += MAX_CLIENTS;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_TranslatePlayerSkin
|
||||
|
||||
Translates a skin texture by the per-player color lookup
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_TranslatePlayerSkin(int playernum)
|
||||
{
|
||||
int top, bottom;
|
||||
byte translate[256];
|
||||
unsigned translate32[256];
|
||||
int i, j, s;
|
||||
model_t *model;
|
||||
aliashdr_t *paliashdr;
|
||||
byte *original;
|
||||
unsigned pixels[512 * 256], *out;
|
||||
unsigned scaled_width, scaled_height;
|
||||
int inwidth, inheight;
|
||||
byte *inrow;
|
||||
unsigned frac, fracstep;
|
||||
|
||||
GL_DisableMultitexture();
|
||||
|
||||
top = cl.scores[playernum].colors & 0xf0;
|
||||
bottom = (cl.scores[playernum].colors & 15) << 4;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
translate[i] = i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (top < 128) // the artists made some backwards ranges. sigh.
|
||||
translate[TOP_RANGE + i] = top + i;
|
||||
else
|
||||
translate[TOP_RANGE + i] = top + 15 - i;
|
||||
|
||||
if (bottom < 128)
|
||||
translate[BOTTOM_RANGE + i] = bottom + i;
|
||||
else
|
||||
translate[BOTTOM_RANGE + i] = bottom + 15 - i;
|
||||
}
|
||||
|
||||
//
|
||||
// locate the original skin pixels
|
||||
//
|
||||
currententity = &cl_entities[1 + playernum];
|
||||
model = currententity->model;
|
||||
if (!model)
|
||||
return; // player doesn't have a model yet
|
||||
if (model->type != mod_alias)
|
||||
return; // only translate skins on alias models
|
||||
|
||||
paliashdr = (aliashdr_t *)Mod_Extradata(model);
|
||||
s = paliashdr->skinwidth * paliashdr->skinheight;
|
||||
if (currententity->skinnum < 0
|
||||
|| currententity->skinnum >= paliashdr->numskins) {
|
||||
Con_Printf("(%d): Invalid player skin #%d\n", playernum,
|
||||
currententity->skinnum);
|
||||
original = (byte *)paliashdr + paliashdr->texels[0];
|
||||
} else
|
||||
original =
|
||||
(byte *)paliashdr + paliashdr->texels[currententity->skinnum];
|
||||
if (s & 3)
|
||||
Sys_Error("%s: s&3", __func__);
|
||||
|
||||
inwidth = paliashdr->skinwidth;
|
||||
inheight = paliashdr->skinheight;
|
||||
|
||||
// because this happens during gameplay, do it fast
|
||||
// instead of sending it through gl_upload 8
|
||||
GL_Bind(playertextures + playernum);
|
||||
|
||||
#if 0
|
||||
byte translated[320 * 200];
|
||||
|
||||
for (i = 0; i < s; i += 4) {
|
||||
translated[i] = translate[original[i]];
|
||||
translated[i + 1] = translate[original[i + 1]];
|
||||
translated[i + 2] = translate[original[i + 2]];
|
||||
translated[i + 3] = translate[original[i + 3]];
|
||||
}
|
||||
|
||||
|
||||
// don't mipmap these, because it takes too long
|
||||
GL_Upload8(translated, paliashdr->skinwidth, paliashdr->skinheight,
|
||||
false, false, true);
|
||||
#else
|
||||
// allow users to crunch sizes down
|
||||
scaled_width = 512 >> (int)gl_playermip.value;
|
||||
scaled_height = 256 >> (int)gl_playermip.value;
|
||||
|
||||
// make sure not still too big
|
||||
scaled_width = gl_max_size.value < scaled_width
|
||||
? gl_max_size.value : scaled_width;
|
||||
scaled_height = gl_max_size.value < scaled_height
|
||||
? gl_max_size.value : scaled_height;
|
||||
|
||||
if (VID_Is8bit()) { // 8bit texture upload
|
||||
byte *out2;
|
||||
|
||||
out2 = (byte *)pixels;
|
||||
memset(pixels, 0, sizeof(pixels));
|
||||
fracstep = inwidth * 0x10000 / scaled_width;
|
||||
for (i = 0; i < scaled_height; i++, out2 += scaled_width) {
|
||||
inrow = original + inwidth * (i * inheight / scaled_height);
|
||||
frac = fracstep >> 1;
|
||||
for (j = 0; j < scaled_width; j += 4) {
|
||||
out2[j] = translate[inrow[frac >> 16]];
|
||||
frac += fracstep;
|
||||
out2[j + 1] = translate[inrow[frac >> 16]];
|
||||
frac += fracstep;
|
||||
out2[j + 2] = translate[inrow[frac >> 16]];
|
||||
frac += fracstep;
|
||||
out2[j + 3] = translate[inrow[frac >> 16]];
|
||||
frac += fracstep;
|
||||
}
|
||||
}
|
||||
|
||||
GL_Upload8_EXT((byte *)pixels, scaled_width, scaled_height, false,
|
||||
false);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
translate32[i] = d_8to24table[translate[i]];
|
||||
|
||||
out = pixels;
|
||||
fracstep = inwidth * 0x10000 / scaled_width;
|
||||
for (i = 0; i < scaled_height; i++, out += scaled_width) {
|
||||
inrow = original + inwidth * (i * inheight / scaled_height);
|
||||
frac = fracstep >> 1;
|
||||
for (j = 0; j < scaled_width; j += 4) {
|
||||
out[j] = translate32[inrow[frac >> 16]];
|
||||
frac += fracstep;
|
||||
out[j + 1] = translate32[inrow[frac >> 16]];
|
||||
frac += fracstep;
|
||||
out[j + 2] = translate32[inrow[frac >> 16]];
|
||||
frac += fracstep;
|
||||
out[j + 3] = translate32[inrow[frac >> 16]];
|
||||
frac += fracstep;
|
||||
}
|
||||
}
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_solid_format, scaled_width,
|
||||
scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_NewMap
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_NewMap(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
d_lightstylevalue[i] = 264; // normal light value
|
||||
|
||||
memset(&r_worldentity, 0, sizeof(r_worldentity));
|
||||
r_worldentity.model = cl.worldmodel;
|
||||
|
||||
// clear out efrags in case the level hasn't been reloaded
|
||||
// FIXME: is this one short?
|
||||
for (i = 0; i < cl.worldmodel->numleafs; i++)
|
||||
cl.worldmodel->leafs[i].efrags = NULL;
|
||||
|
||||
r_viewleaf = NULL;
|
||||
R_ClearParticles();
|
||||
|
||||
GL_BuildLightmaps();
|
||||
|
||||
// identify sky texture
|
||||
skytexturenum = -1;
|
||||
mirrortexturenum = -1;
|
||||
for (i = 0; i < cl.worldmodel->numtextures; i++) {
|
||||
if (!cl.worldmodel->textures[i])
|
||||
continue;
|
||||
if (!strncmp(cl.worldmodel->textures[i]->name, "sky", 3))
|
||||
skytexturenum = i;
|
||||
if (!strncmp(cl.worldmodel->textures[i]->name, "window02_1", 10))
|
||||
mirrortexturenum = i;
|
||||
cl.worldmodel->textures[i]->texturechain = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
R_TimeRefresh_f
|
||||
|
||||
For program optimization
|
||||
====================
|
||||
*/
|
||||
void
|
||||
R_TimeRefresh_f(void)
|
||||
{
|
||||
int i;
|
||||
float start, stop, time;
|
||||
|
||||
glDrawBuffer(GL_FRONT);
|
||||
glFinish();
|
||||
|
||||
start = Sys_DoubleTime();
|
||||
for (i = 0; i < 128; i++) {
|
||||
r_refdef.viewangles[1] = i / 128.0 * 360.0;
|
||||
R_RenderView();
|
||||
}
|
||||
|
||||
glFinish();
|
||||
stop = Sys_DoubleTime();
|
||||
time = stop - start;
|
||||
Con_Printf("%f seconds (%f fps)\n", time, 128 / time);
|
||||
|
||||
glDrawBuffer(GL_BACK);
|
||||
GL_EndRendering();
|
||||
}
|
||||
|
||||
void
|
||||
D_FlushCaches(void)
|
||||
{
|
||||
}
|
910
NQ/gl_screen.c
Normal file
910
NQ/gl_screen.c
Normal file
@ -0,0 +1,910 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// screen.c -- master for refresh, status bar, console, chat, notify, etc
|
||||
|
||||
#include "cmd.h"
|
||||
#include "console.h"
|
||||
#include "draw.h"
|
||||
#include "glquake.h"
|
||||
#include "host.h"
|
||||
#include "keys.h"
|
||||
#include "menu.h"
|
||||
#include "quakedef.h"
|
||||
#include "sbar.h"
|
||||
#include "screen.h"
|
||||
#include "sound.h"
|
||||
#include "sys.h"
|
||||
#include "view.h"
|
||||
#include "wad.h"
|
||||
|
||||
/*
|
||||
|
||||
background clear
|
||||
rendering
|
||||
turtle/net/ram icons
|
||||
sbar
|
||||
centerprint / slow centerprint
|
||||
notify lines
|
||||
intermission / finale overlay
|
||||
loading plaque
|
||||
console
|
||||
menu
|
||||
|
||||
required background clears
|
||||
required update regions
|
||||
|
||||
syncronous draw mode or async
|
||||
One off screen buffer, with updates either copied or xblited
|
||||
Need to double buffer?
|
||||
|
||||
async draw will require the refresh area to be cleared, because it will be
|
||||
xblited, but sync draw can just ignore it.
|
||||
|
||||
sync
|
||||
draw
|
||||
|
||||
CenterPrint()
|
||||
SlowPrint()
|
||||
Screen_Update();
|
||||
Con_Printf();
|
||||
|
||||
net
|
||||
turn off messages option
|
||||
|
||||
the refresh is always rendered, unless the console is full screen
|
||||
|
||||
console is:
|
||||
notify lines
|
||||
half
|
||||
full
|
||||
*/
|
||||
|
||||
|
||||
int glx, gly, glwidth, glheight;
|
||||
|
||||
// only the refresh window will be updated unless these variables are flagged
|
||||
int scr_copytop;
|
||||
int scr_copyeverything;
|
||||
|
||||
float scr_con_current;
|
||||
float scr_conlines; // lines of console to display
|
||||
|
||||
float oldscreensize, oldfov;
|
||||
cvar_t scr_viewsize = { "viewsize", "100", true };
|
||||
cvar_t scr_fov = { "fov", "90" }; // 10 - 170
|
||||
cvar_t scr_conspeed = { "scr_conspeed", "300" };
|
||||
cvar_t scr_centertime = { "scr_centertime", "2" };
|
||||
cvar_t scr_showram = { "showram", "1" };
|
||||
cvar_t scr_showturtle = { "showturtle", "0" };
|
||||
cvar_t scr_showpause = { "showpause", "1" };
|
||||
cvar_t scr_printspeed = { "scr_printspeed", "8" };
|
||||
cvar_t gl_triplebuffer = { "gl_triplebuffer", "1", true };
|
||||
|
||||
qboolean scr_initialized; // ready to draw
|
||||
|
||||
qpic_t *scr_ram;
|
||||
qpic_t *scr_net;
|
||||
qpic_t *scr_turtle;
|
||||
|
||||
int scr_fullupdate;
|
||||
|
||||
int clearconsole;
|
||||
int clearnotify;
|
||||
|
||||
int sb_lines;
|
||||
|
||||
viddef_t vid; // global video state
|
||||
|
||||
vrect_t scr_vrect;
|
||||
|
||||
qboolean scr_disabled_for_loading;
|
||||
qboolean scr_drawloading;
|
||||
float scr_disabled_time;
|
||||
|
||||
qboolean block_drawing;
|
||||
|
||||
void SCR_ScreenShot_f(void);
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
CENTER PRINTING
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
char scr_centerstring[1024];
|
||||
float scr_centertime_start; // for slow victory printing
|
||||
float scr_centertime_off;
|
||||
int scr_center_lines;
|
||||
int scr_erase_lines;
|
||||
int scr_erase_center;
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_CenterPrint
|
||||
|
||||
Called for important messages that should stay in the center of the screen
|
||||
for a few moments
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_CenterPrint(char *str)
|
||||
{
|
||||
strncpy(scr_centerstring, str, sizeof(scr_centerstring) - 1);
|
||||
scr_centertime_off = scr_centertime.value;
|
||||
scr_centertime_start = cl.time;
|
||||
|
||||
// count the number of lines for centering
|
||||
scr_center_lines = 1;
|
||||
while (*str) {
|
||||
if (*str == '\n')
|
||||
scr_center_lines++;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SCR_DrawCenterString(void)
|
||||
{
|
||||
char *start;
|
||||
int l;
|
||||
int j;
|
||||
int x, y;
|
||||
int remaining;
|
||||
|
||||
// the finale prints the characters one at a time
|
||||
if (cl.intermission)
|
||||
remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
|
||||
else
|
||||
remaining = 9999;
|
||||
|
||||
scr_erase_center = 0;
|
||||
start = scr_centerstring;
|
||||
|
||||
if (scr_center_lines <= 4)
|
||||
y = vid.height * 0.35;
|
||||
else
|
||||
y = 48;
|
||||
|
||||
do {
|
||||
// scan the width of the line
|
||||
for (l = 0; l < 40; l++)
|
||||
if (start[l] == '\n' || !start[l])
|
||||
break;
|
||||
x = (vid.width - l * 8) / 2;
|
||||
for (j = 0; j < l; j++, x += 8) {
|
||||
Draw_Character(x, y, start[j]);
|
||||
if (!remaining--)
|
||||
return;
|
||||
}
|
||||
|
||||
y += 8;
|
||||
|
||||
while (*start && *start != '\n')
|
||||
start++;
|
||||
|
||||
if (!*start)
|
||||
break;
|
||||
start++; // skip the \n
|
||||
} while (1);
|
||||
}
|
||||
|
||||
void
|
||||
SCR_CheckDrawCenterString(void)
|
||||
{
|
||||
scr_copytop = 1;
|
||||
if (scr_center_lines > scr_erase_lines)
|
||||
scr_erase_lines = scr_center_lines;
|
||||
|
||||
scr_centertime_off -= host_frametime;
|
||||
|
||||
if (scr_centertime_off <= 0 && !cl.intermission)
|
||||
return;
|
||||
if (key_dest != key_game)
|
||||
return;
|
||||
|
||||
SCR_DrawCenterString();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
====================
|
||||
CalcFov
|
||||
====================
|
||||
*/
|
||||
float
|
||||
CalcFov(float fov_x, float width, float height)
|
||||
{
|
||||
float a;
|
||||
float x;
|
||||
|
||||
if (fov_x < 1 || fov_x > 179)
|
||||
Sys_Error("Bad fov: %f", fov_x);
|
||||
|
||||
x = width / tan(fov_x / 360 * M_PI);
|
||||
a = atan(height / x);
|
||||
a = a * 360 / M_PI;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SCR_CalcRefdef
|
||||
|
||||
Must be called whenever vid changes
|
||||
Internal use only
|
||||
=================
|
||||
*/
|
||||
static void
|
||||
SCR_CalcRefdef(void)
|
||||
{
|
||||
float size;
|
||||
int h;
|
||||
qboolean full = false;
|
||||
|
||||
|
||||
scr_fullupdate = 0; // force a background redraw
|
||||
vid.recalc_refdef = 0;
|
||||
|
||||
// force the status bar to redraw
|
||||
Sbar_Changed();
|
||||
|
||||
//========================================
|
||||
|
||||
// bound viewsize
|
||||
if (scr_viewsize.value < 30)
|
||||
Cvar_Set("viewsize", "30");
|
||||
if (scr_viewsize.value > 120)
|
||||
Cvar_Set("viewsize", "120");
|
||||
|
||||
// bound field of view
|
||||
if (scr_fov.value < 10)
|
||||
Cvar_Set("fov", "10");
|
||||
if (scr_fov.value > 170)
|
||||
Cvar_Set("fov", "170");
|
||||
|
||||
// intermission is always full screen
|
||||
if (cl.intermission)
|
||||
size = 120;
|
||||
else
|
||||
size = scr_viewsize.value;
|
||||
|
||||
if (size >= 120)
|
||||
sb_lines = 0; // no status bar at all
|
||||
else if (size >= 110)
|
||||
sb_lines = 24; // no inventory
|
||||
else
|
||||
sb_lines = 24 + 16 + 8;
|
||||
|
||||
if (scr_viewsize.value >= 100.0) {
|
||||
full = true;
|
||||
size = 100.0;
|
||||
} else
|
||||
size = scr_viewsize.value;
|
||||
if (cl.intermission) {
|
||||
full = true;
|
||||
size = 100;
|
||||
sb_lines = 0;
|
||||
}
|
||||
size /= 100.0;
|
||||
|
||||
h = vid.height - sb_lines;
|
||||
|
||||
r_refdef.vrect.width = vid.width * size;
|
||||
if (r_refdef.vrect.width < 96) {
|
||||
size = 96.0 / r_refdef.vrect.width;
|
||||
r_refdef.vrect.width = 96; // min for icons
|
||||
}
|
||||
|
||||
r_refdef.vrect.height = vid.height * size;
|
||||
if (r_refdef.vrect.height > vid.height - sb_lines)
|
||||
r_refdef.vrect.height = vid.height - sb_lines;
|
||||
if (r_refdef.vrect.height > vid.height)
|
||||
r_refdef.vrect.height = vid.height;
|
||||
r_refdef.vrect.x = (vid.width - r_refdef.vrect.width) / 2;
|
||||
if (full)
|
||||
r_refdef.vrect.y = 0;
|
||||
else
|
||||
r_refdef.vrect.y = (h - r_refdef.vrect.height) / 2;
|
||||
|
||||
r_refdef.fov_x = scr_fov.value;
|
||||
r_refdef.fov_y =
|
||||
CalcFov(r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
|
||||
|
||||
scr_vrect = r_refdef.vrect;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SCR_SizeUp_f
|
||||
|
||||
Keybinding command
|
||||
=================
|
||||
*/
|
||||
void
|
||||
SCR_SizeUp_f(void)
|
||||
{
|
||||
Cvar_SetValue("viewsize", scr_viewsize.value + 10);
|
||||
vid.recalc_refdef = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SCR_SizeDown_f
|
||||
|
||||
Keybinding command
|
||||
=================
|
||||
*/
|
||||
void
|
||||
SCR_SizeDown_f(void)
|
||||
{
|
||||
Cvar_SetValue("viewsize", scr_viewsize.value - 10);
|
||||
vid.recalc_refdef = 1;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_Init
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_Init(void)
|
||||
{
|
||||
|
||||
Cvar_RegisterVariable(&scr_fov);
|
||||
Cvar_RegisterVariable(&scr_viewsize);
|
||||
Cvar_RegisterVariable(&scr_conspeed);
|
||||
Cvar_RegisterVariable(&scr_showram);
|
||||
Cvar_RegisterVariable(&scr_showturtle);
|
||||
Cvar_RegisterVariable(&scr_showpause);
|
||||
Cvar_RegisterVariable(&scr_centertime);
|
||||
Cvar_RegisterVariable(&scr_printspeed);
|
||||
Cvar_RegisterVariable(&gl_triplebuffer);
|
||||
|
||||
//
|
||||
// register our commands
|
||||
//
|
||||
Cmd_AddCommand("screenshot", SCR_ScreenShot_f);
|
||||
Cmd_AddCommand("sizeup", SCR_SizeUp_f);
|
||||
Cmd_AddCommand("sizedown", SCR_SizeDown_f);
|
||||
|
||||
scr_ram = Draw_PicFromWad("ram");
|
||||
scr_net = Draw_PicFromWad("net");
|
||||
scr_turtle = Draw_PicFromWad("turtle");
|
||||
|
||||
scr_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_DrawRam
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawRam(void)
|
||||
{
|
||||
if (!scr_showram.value)
|
||||
return;
|
||||
|
||||
if (!r_cache_thrash)
|
||||
return;
|
||||
|
||||
Draw_Pic(scr_vrect.x + 32, scr_vrect.y, scr_ram);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_DrawTurtle
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawTurtle(void)
|
||||
{
|
||||
static int count;
|
||||
|
||||
if (!scr_showturtle.value)
|
||||
return;
|
||||
|
||||
if (host_frametime < 0.1) {
|
||||
count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
if (count < 3)
|
||||
return;
|
||||
|
||||
Draw_Pic(scr_vrect.x, scr_vrect.y, scr_turtle);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_DrawNet
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawNet(void)
|
||||
{
|
||||
if (realtime - cl.last_received_message < 0.3)
|
||||
return;
|
||||
if (cls.demoplayback)
|
||||
return;
|
||||
|
||||
Draw_Pic(scr_vrect.x + 64, scr_vrect.y, scr_net);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
DrawPause
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawPause(void)
|
||||
{
|
||||
qpic_t *pic;
|
||||
|
||||
if (!scr_showpause.value) // turn off for screenshots
|
||||
return;
|
||||
|
||||
if (!cl.paused)
|
||||
return;
|
||||
|
||||
pic = Draw_CachePic("gfx/pause.lmp");
|
||||
Draw_Pic((vid.width - pic->width) / 2,
|
||||
(vid.height - 48 - pic->height) / 2, pic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_DrawLoading
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawLoading(void)
|
||||
{
|
||||
qpic_t *pic;
|
||||
|
||||
if (!scr_drawloading)
|
||||
return;
|
||||
|
||||
pic = Draw_CachePic("gfx/loading.lmp");
|
||||
Draw_Pic((vid.width - pic->width) / 2,
|
||||
(vid.height - 48 - pic->height) / 2, pic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_SetUpToDrawConsole
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_SetUpToDrawConsole(void)
|
||||
{
|
||||
Con_CheckResize();
|
||||
|
||||
if (scr_drawloading)
|
||||
return; // never a console with loading plaque
|
||||
|
||||
// decide on the height of the console
|
||||
con_forcedup = !cl.worldmodel || cls.state != ca_active;
|
||||
|
||||
if (con_forcedup) {
|
||||
scr_conlines = vid.height; // full screen
|
||||
scr_con_current = scr_conlines;
|
||||
} else if (key_dest == key_console)
|
||||
scr_conlines = vid.height / 2; // half screen
|
||||
else
|
||||
scr_conlines = 0; // none visible
|
||||
|
||||
if (scr_conlines < scr_con_current) {
|
||||
scr_con_current -= scr_conspeed.value * host_frametime;
|
||||
if (scr_conlines > scr_con_current)
|
||||
scr_con_current = scr_conlines;
|
||||
|
||||
} else if (scr_conlines > scr_con_current) {
|
||||
scr_con_current += scr_conspeed.value * host_frametime;
|
||||
if (scr_conlines < scr_con_current)
|
||||
scr_con_current = scr_conlines;
|
||||
}
|
||||
|
||||
if (clearconsole++ < vid.numpages) {
|
||||
Sbar_Changed();
|
||||
} else if (clearnotify++ < vid.numpages) {
|
||||
} else
|
||||
con_notifylines = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_DrawConsole
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_DrawConsole(void)
|
||||
{
|
||||
if (scr_con_current) {
|
||||
scr_copyeverything = 1;
|
||||
Con_DrawConsole(scr_con_current);
|
||||
clearconsole = 0;
|
||||
} else {
|
||||
if (key_dest == key_game || key_dest == key_message)
|
||||
Con_DrawNotify(); // only draw notify in game
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
SCREEN SHOTS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
typedef struct _TargaHeader {
|
||||
unsigned char id_length, colormap_type, image_type;
|
||||
unsigned short colormap_index, colormap_length;
|
||||
unsigned char colormap_size;
|
||||
unsigned short x_origin, y_origin, width, height;
|
||||
unsigned char pixel_size, attributes;
|
||||
} TargaHeader;
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_ScreenShot_f
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_ScreenShot_f(void)
|
||||
{
|
||||
byte *buffer;
|
||||
char pcxname[80];
|
||||
char checkname[MAX_OSPATH];
|
||||
int i, c, temp;
|
||||
|
||||
//
|
||||
// find a file name to save it to
|
||||
//
|
||||
strcpy(pcxname, "quake00.tga");
|
||||
|
||||
for (i = 0; i <= 99; i++) {
|
||||
pcxname[5] = i / 10 + '0';
|
||||
pcxname[6] = i % 10 + '0';
|
||||
sprintf(checkname, "%s/%s", com_gamedir, pcxname);
|
||||
if (Sys_FileTime(checkname) == -1)
|
||||
break; // file doesn't exist
|
||||
}
|
||||
if (i == 100) {
|
||||
Con_Printf("SCR_ScreenShot_f: Couldn't create a PCX file\n");
|
||||
return;
|
||||
}
|
||||
// FIXME - this is a PCX header?
|
||||
buffer = malloc(glwidth * glheight * 3 + 18);
|
||||
memset(buffer, 0, 18);
|
||||
buffer[2] = 2; // uncompressed type
|
||||
buffer[12] = glwidth & 255;
|
||||
buffer[13] = glwidth >> 8;
|
||||
buffer[14] = glheight & 255;
|
||||
buffer[15] = glheight >> 8;
|
||||
buffer[16] = 24; // pixel size
|
||||
|
||||
glReadPixels(glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE,
|
||||
buffer + 18);
|
||||
|
||||
// swap rgb to bgr
|
||||
c = 18 + glwidth * glheight * 3;
|
||||
for (i = 18; i < c; i += 3) {
|
||||
temp = buffer[i];
|
||||
buffer[i] = buffer[i + 2];
|
||||
buffer[i + 2] = temp;
|
||||
}
|
||||
COM_WriteFile(pcxname, buffer, glwidth * glheight * 3 + 18);
|
||||
|
||||
free(buffer);
|
||||
Con_Printf("Wrote %s\n", pcxname);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
SCR_BeginLoadingPlaque
|
||||
|
||||
================
|
||||
*/
|
||||
void
|
||||
SCR_BeginLoadingPlaque(void)
|
||||
{
|
||||
S_StopAllSounds(true);
|
||||
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
// redraw with no console and the loading plaque
|
||||
Con_ClearNotify();
|
||||
scr_centertime_off = 0;
|
||||
scr_con_current = 0;
|
||||
|
||||
scr_drawloading = true;
|
||||
scr_fullupdate = 0;
|
||||
Sbar_Changed();
|
||||
SCR_UpdateScreen();
|
||||
scr_drawloading = false;
|
||||
|
||||
scr_disabled_for_loading = true;
|
||||
scr_disabled_time = realtime;
|
||||
scr_fullupdate = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SCR_EndLoadingPlaque
|
||||
|
||||
================
|
||||
*/
|
||||
void
|
||||
SCR_EndLoadingPlaque(void)
|
||||
{
|
||||
scr_disabled_for_loading = false;
|
||||
scr_fullupdate = 0;
|
||||
Con_ClearNotify();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
char *scr_notifystring;
|
||||
qboolean scr_drawdialog;
|
||||
|
||||
void
|
||||
SCR_DrawNotifyString(void)
|
||||
{
|
||||
char *start;
|
||||
int l;
|
||||
int j;
|
||||
int x, y;
|
||||
|
||||
start = scr_notifystring;
|
||||
|
||||
y = vid.height * 0.35;
|
||||
|
||||
do {
|
||||
// scan the width of the line
|
||||
for (l = 0; l < 40; l++)
|
||||
if (start[l] == '\n' || !start[l])
|
||||
break;
|
||||
x = (vid.width - l * 8) / 2;
|
||||
for (j = 0; j < l; j++, x += 8)
|
||||
Draw_Character(x, y, start[j]);
|
||||
|
||||
y += 8;
|
||||
|
||||
while (*start && *start != '\n')
|
||||
start++;
|
||||
|
||||
if (!*start)
|
||||
break;
|
||||
start++; // skip the \n
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_ModalMessage
|
||||
|
||||
Displays a text string in the center of the screen and waits for a Y or N
|
||||
keypress.
|
||||
==================
|
||||
*/
|
||||
int
|
||||
SCR_ModalMessage(char *text)
|
||||
{
|
||||
if (cls.state == ca_dedicated)
|
||||
return true;
|
||||
|
||||
scr_notifystring = text;
|
||||
|
||||
// draw a fresh screen
|
||||
scr_fullupdate = 0;
|
||||
scr_drawdialog = true;
|
||||
SCR_UpdateScreen();
|
||||
scr_drawdialog = false;
|
||||
|
||||
S_ClearBuffer(); // so dma doesn't loop current sound
|
||||
|
||||
do {
|
||||
key_count = -1; // wait for a key down and up
|
||||
Sys_SendKeyEvents();
|
||||
} while (key_lastpress != 'y' && key_lastpress != 'n'
|
||||
&& key_lastpress != K_ESCAPE);
|
||||
|
||||
scr_fullupdate = 0;
|
||||
SCR_UpdateScreen();
|
||||
|
||||
return key_lastpress == 'y';
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
===============
|
||||
SCR_BringDownConsole
|
||||
|
||||
Brings the console down and fades the palettes back to normal
|
||||
================
|
||||
*/
|
||||
void
|
||||
SCR_BringDownConsole(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
scr_centertime_off = 0;
|
||||
|
||||
for (i = 0; i < 20 && scr_conlines != scr_con_current; i++)
|
||||
SCR_UpdateScreen();
|
||||
|
||||
cl.cshifts[0].percent = 0; // no area contents palette on next frame
|
||||
VID_SetPalette(host_basepal);
|
||||
}
|
||||
|
||||
void
|
||||
SCR_TileClear(void)
|
||||
{
|
||||
if (r_refdef.vrect.x > 0) {
|
||||
// left
|
||||
Draw_TileClear(0, 0, r_refdef.vrect.x, vid.height - sb_lines);
|
||||
// right
|
||||
Draw_TileClear(r_refdef.vrect.x + r_refdef.vrect.width, 0,
|
||||
vid.width - r_refdef.vrect.x + r_refdef.vrect.width,
|
||||
vid.height - sb_lines);
|
||||
}
|
||||
if (r_refdef.vrect.y > 0) {
|
||||
// top
|
||||
Draw_TileClear(r_refdef.vrect.x, 0,
|
||||
r_refdef.vrect.x + r_refdef.vrect.width,
|
||||
r_refdef.vrect.y);
|
||||
// bottom
|
||||
Draw_TileClear(r_refdef.vrect.x,
|
||||
r_refdef.vrect.y + r_refdef.vrect.height,
|
||||
r_refdef.vrect.width,
|
||||
vid.height - sb_lines -
|
||||
(r_refdef.vrect.height + r_refdef.vrect.y));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_UpdateScreen
|
||||
|
||||
This is called every frame, and can also be called explicitly to flush
|
||||
text to the screen.
|
||||
|
||||
WARNING: be very careful calling this from elsewhere, because the refresh
|
||||
needs almost the entire 256k of stack space!
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_UpdateScreen(void)
|
||||
{
|
||||
if (block_drawing)
|
||||
return;
|
||||
|
||||
vid.numpages = 2 + gl_triplebuffer.value;
|
||||
|
||||
scr_copytop = 0;
|
||||
scr_copyeverything = 0;
|
||||
|
||||
if (scr_disabled_for_loading) {
|
||||
if (realtime - scr_disabled_time > 60) {
|
||||
scr_disabled_for_loading = false;
|
||||
Con_Printf("load failed.\n");
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scr_initialized || !con_initialized)
|
||||
return; // not initialized yet
|
||||
|
||||
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
||||
|
||||
//
|
||||
// determine size of refresh window
|
||||
//
|
||||
if (oldfov != scr_fov.value) {
|
||||
oldfov = scr_fov.value;
|
||||
vid.recalc_refdef = true;
|
||||
}
|
||||
|
||||
if (oldscreensize != scr_viewsize.value) {
|
||||
oldscreensize = scr_viewsize.value;
|
||||
vid.recalc_refdef = true;
|
||||
}
|
||||
|
||||
if (vid.recalc_refdef)
|
||||
SCR_CalcRefdef();
|
||||
|
||||
//
|
||||
// do 3D refresh drawing, and then update the screen
|
||||
//
|
||||
SCR_SetUpToDrawConsole();
|
||||
|
||||
V_RenderView();
|
||||
|
||||
GL_Set2D();
|
||||
|
||||
//
|
||||
// draw any areas not covered by the refresh
|
||||
//
|
||||
SCR_TileClear();
|
||||
|
||||
if (scr_drawdialog) {
|
||||
Sbar_Draw();
|
||||
Draw_FadeScreen();
|
||||
SCR_DrawNotifyString();
|
||||
scr_copyeverything = true;
|
||||
} else if (scr_drawloading) {
|
||||
SCR_DrawLoading();
|
||||
Sbar_Draw();
|
||||
} else if (cl.intermission == 1 && key_dest == key_game) {
|
||||
Sbar_IntermissionOverlay();
|
||||
} else if (cl.intermission == 2 && key_dest == key_game) {
|
||||
Sbar_FinaleOverlay();
|
||||
SCR_CheckDrawCenterString();
|
||||
} else {
|
||||
if (crosshair.value) {
|
||||
//Draw_Crosshair();
|
||||
Draw_Character(scr_vrect.x + scr_vrect.width / 2,
|
||||
scr_vrect.y + scr_vrect.height / 2, '+');
|
||||
}
|
||||
SCR_DrawRam();
|
||||
SCR_DrawNet();
|
||||
SCR_DrawTurtle();
|
||||
SCR_DrawPause();
|
||||
SCR_CheckDrawCenterString();
|
||||
Sbar_Draw();
|
||||
SCR_DrawConsole();
|
||||
M_Draw();
|
||||
}
|
||||
|
||||
V_UpdatePalette();
|
||||
|
||||
GL_EndRendering();
|
||||
}
|
171
NQ/glqnotes.txt
Normal file
171
NQ/glqnotes.txt
Normal file
@ -0,0 +1,171 @@
|
||||
Glquake v0.99, Quake v1.09 release notes
|
||||
|
||||
3dfx owners -- read the 3dfx.txt file.
|
||||
|
||||
On a standard OpenGL system, all you should need to do to run glquake is put
|
||||
glquake.exe in your quake directory, and run it from there. DO NOT install
|
||||
the opengl32.dll unless you have a 3dfx! Glquake should change the screen
|
||||
resolution to 640*480*32k colors and run full screen by default.
|
||||
|
||||
If you are running win-95, your desktop must be set to 32k or 64k colors
|
||||
before running glquake. NT can switch automatically.
|
||||
|
||||
Theoretically, glquake will run on any compliant OpenGL that supports the
|
||||
texture objects extensions, but unless it is very powerfull hardware that
|
||||
accelerates everything needed, the game play will not be acceptable. If it
|
||||
has to go through any software emulation paths, the performance will likely
|
||||
by well under one frame per second.
|
||||
|
||||
3dfx has provided an opengl32.dll that implements everything glquake needs,
|
||||
but it is not a full opengl implementation. Other opengl applications are
|
||||
very unlikely to work with it, so consider it basically a "glquake driver".
|
||||
See the encluded 3dfx.txt for specific instalation notes. 3dfx can only run
|
||||
full screen, but you must still have your desktop set to a 16 bit color mode
|
||||
for glquake to start.
|
||||
|
||||
resolution options
|
||||
------------------
|
||||
We had dynamic resolution changing in glquake for a while, but every single
|
||||
opengl driver I tried it on messed up in one way or another, so it is now
|
||||
limited to startup time only.
|
||||
|
||||
glquake -window
|
||||
This will start glquake in a window on your desktop instead of switching the
|
||||
screen to lower resolution and covering everything.
|
||||
|
||||
glquake -width 800 -height 600
|
||||
Tries to run glquake at the specified resolution. Combined with -window, it
|
||||
creates a desktop window that size, otherwise it tries to set a full screen
|
||||
resolution.
|
||||
|
||||
You can also specify the resolution of the console independant of the screen
|
||||
resolution.
|
||||
|
||||
glquake -conwidth 320
|
||||
This will specify a console resolution of 320 by 240 (the height is
|
||||
automatically determined by the default 4:3 aspect ratio, you can also
|
||||
specify the height directly with -conheight).
|
||||
|
||||
In higher resolution modes such as 800x600 and 1024x768, glquake will default
|
||||
to a 640x480 console, since the font becomes small enough at higher
|
||||
resolutions to become unreadable. If do you wish to have a higher resolution
|
||||
console and status bar, specify it as well, such as:
|
||||
glquake -width 800 -height 600 -conwidth 800
|
||||
|
||||
texture options
|
||||
---------------
|
||||
The amount of textures used in the game can have a large impact on performance.
|
||||
There are several options that let you trade off visual quality for better
|
||||
performance.
|
||||
|
||||
There is no way to flush already loaded textures, so it is best to change
|
||||
these options on the command line, or they will only take effect on some of
|
||||
the textures when you change levels.
|
||||
|
||||
OpenGL only allows textures to repeat on power of two boundaries (32, 64,
|
||||
128, etc), but software quake had a number of textures that repeated at 24
|
||||
or 96 pixel boundaries. These need to be either stretched out to the next
|
||||
higher size, or shrunk down to the next lower. By default, they are filtered
|
||||
down to the smaller size, but you can cause it to use the larger size if you
|
||||
really want by using:
|
||||
|
||||
glquake +gl_round_down 0
|
||||
This will generally run well on a normal 4 MB 3dfx card, but for other cards
|
||||
that have either worse texture management or slower texture swapping speeds,
|
||||
there are some additional settings that can drastically lower the amount of
|
||||
textures to be managed.
|
||||
|
||||
glquake +gl_picmip 1
|
||||
This causes all textures to have one half the dimensions they otherwise would.
|
||||
This makes them blurry, but very small. You can set this to 2 to make the
|
||||
textures one quarter the resolution on each axis for REALLY blurry textures.
|
||||
|
||||
glquake +gl_playermip 1
|
||||
This is similar to picmip, but is only used for other players in deathmatch.
|
||||
Each player in a deathmatch requires an individual skin texture, so this can
|
||||
be a serious problem for texture management. It wouldn't be unreasonable to
|
||||
set this to 2 or even 3 if you are playing competatively (and don't care if
|
||||
the other guys have smudged skins). If you change this during the game, it
|
||||
will take effect as soon as a player changes their skin colors.
|
||||
|
||||
GLQuake also supports the following extensions for faster texture operation:
|
||||
|
||||
GL_SGIS_multitexture
|
||||
Multitextures support allows certain hardware to render the world in one
|
||||
pass instead of two. GLQuake uses two passes, one for the world textures
|
||||
and the second for the lightmaps that are blended on the textures. On some
|
||||
hardware, with a GL_SIGS_multitexture supported OpenGL implementation, this
|
||||
can be done in one pass. On hardware that supports this, you will get a
|
||||
60% to 100% increase in frame rate. Currently, only 3DFX dual TMU cards
|
||||
(such as the Obsidian 2220) support this extension, but other hardware will
|
||||
soon follow.
|
||||
|
||||
This extension will be autodetected and used. If for some reason it is not
|
||||
working correctly, specify the command line option "-nomtex" to disable it.
|
||||
|
||||
GL_EXT_shared_texture_palette
|
||||
GLQuake uses 16bit textures by default but on OpenGL implementations
|
||||
that support the GL_EXT_shared_texture_palette extension, GLQuake will use
|
||||
8bit textures instead. This results in using half the needed texture memory
|
||||
of 16bit texture and can improve performance. This is very little difference
|
||||
in visual quality due to the fact that the textures are 8bit sources to
|
||||
begin with.
|
||||
|
||||
run time options
|
||||
----------------
|
||||
At the console, you can set these values to effect drawing.
|
||||
|
||||
gl_texturemode GL_NEAREST
|
||||
Sets texture mapping to point sampled, which may be faster on some GL systems
|
||||
(not on 3dfx).
|
||||
|
||||
gl_texturemode GL_LINEAR_MIPMAP
|
||||
This is the default texture mode.
|
||||
|
||||
gl_texturemode GL_LINEAR_MIPMAP_LINEAR
|
||||
This is the highest quality texture mapping (trilinear), but only very high
|
||||
end hardware (intergraph intense 3D / realizm) supports it. Not that big of
|
||||
a deal, actually.
|
||||
|
||||
gl_finish 0
|
||||
This causes the game to not issue a glFinish() call each frame, which may make
|
||||
some hardware run faster. If this is cleared, the 3dfx will back up a number
|
||||
of frames and not be very playable.
|
||||
|
||||
gl_flashblend 0
|
||||
By default, glquake just draws a shaded ball around objects that are emiting
|
||||
light. Clearing this variable will cause it to properly relight the world
|
||||
like normal quake, but it can be a significant speed hit on some systems.
|
||||
|
||||
gl_ztrick 0
|
||||
Glquake uses a buffering method that avoids clearing the Z buffer, but some
|
||||
hardware platforms don't like it. If the status bar and console are flashing
|
||||
every other frame, clear this variable.
|
||||
|
||||
gl_keeptjunctions 0
|
||||
If you clear this, glquake will remove colinear vertexes when it reloads the
|
||||
level. This can give a few percent speedup, but it can leave a couple stray
|
||||
blinking pixels on the screen.
|
||||
|
||||
novelty features
|
||||
----------------
|
||||
These are some rendering tricks that were easy to do in glquake. They aren't
|
||||
very robust, but they are pretty cool to look at.
|
||||
|
||||
r_shadows 1
|
||||
This causes every object to cast a shadow.
|
||||
|
||||
r_wateralpha 0.7
|
||||
This sets the opacity of water textures, so you can see through it in properly
|
||||
processed maps. 0.3 is very faint, almost like fog. 1 is completely solid
|
||||
(the default). Unfortunately, the standard quake maps don't contain any
|
||||
visibility information for seeing past water surfaces, so you can't just play
|
||||
quake with this turned on. If you just want to see what it looks like, you
|
||||
can set "r_novis 1", but that will make things go very slow. When I get a
|
||||
chance, I will probably release some maps that have been processed properly
|
||||
for this.
|
||||
|
||||
r_mirroralpha 0.3
|
||||
This changes one particular texture (the stained glass texture in the EASY
|
||||
start hall) into a mirror. The value is the opacity of the mirror surface.
|
||||
|
986
NQ/host.c
Normal file
986
NQ/host.c
Normal file
@ -0,0 +1,986 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// host.c -- coordinates spawning and killing of local servers
|
||||
|
||||
#include "cdaudio.h"
|
||||
#include "cmd.h"
|
||||
#include "console.h"
|
||||
#include "draw.h"
|
||||
#include "host.h"
|
||||
#include "input.h"
|
||||
#include "keys.h"
|
||||
#include "menu.h"
|
||||
#include "net.h"
|
||||
#include "net_vcr.h"
|
||||
#include "protocol.h"
|
||||
#include "quakedef.h"
|
||||
#include "sbar.h"
|
||||
#include "screen.h"
|
||||
#include "server.h"
|
||||
#include "sound.h"
|
||||
#include "sys.h"
|
||||
#include "view.h"
|
||||
#include "wad.h"
|
||||
|
||||
#ifdef GLQUAKE
|
||||
#include "gl_model.h"
|
||||
#else
|
||||
#include "r_local.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A server can allways be started, even if the system started out as a client
|
||||
* to a remote system.
|
||||
*
|
||||
* A client can NOT be started if the system started as a dedicated server.
|
||||
*
|
||||
* Memory is cleared/released when a server or client begins, not when they
|
||||
* end.
|
||||
*/
|
||||
|
||||
quakeparms_t host_parms;
|
||||
|
||||
qboolean host_initialized; // true if into command execution
|
||||
|
||||
double host_frametime;
|
||||
double host_time;
|
||||
double realtime; // without any filtering or bounding
|
||||
double oldrealtime; // last frame run
|
||||
int host_framecount;
|
||||
|
||||
int host_hunklevel;
|
||||
|
||||
int minimum_memory;
|
||||
|
||||
client_t *host_client; // current client
|
||||
|
||||
jmp_buf host_abortserver;
|
||||
|
||||
byte *host_basepal;
|
||||
byte *host_colormap;
|
||||
|
||||
cvar_t host_framerate = { "host_framerate", "0" }; // set for slow motion
|
||||
cvar_t host_speeds = { "host_speeds", "0" }; // set for running times
|
||||
|
||||
cvar_t sys_ticrate = { "sys_ticrate", "0.05" };
|
||||
cvar_t serverprofile = { "serverprofile", "0" };
|
||||
|
||||
cvar_t fraglimit = { "fraglimit", "0", false, true };
|
||||
cvar_t timelimit = { "timelimit", "0", false, true };
|
||||
cvar_t teamplay = { "teamplay", "0", false, true };
|
||||
|
||||
cvar_t samelevel = { "samelevel", "0" };
|
||||
cvar_t noexit = { "noexit", "0", false, true };
|
||||
|
||||
cvar_t developer = { "developer", "0" };
|
||||
|
||||
cvar_t skill = { "skill", "1" }; // 0 - 3
|
||||
cvar_t deathmatch = { "deathmatch", "0" }; // 0, 1, or 2
|
||||
cvar_t coop = { "coop", "0" }; // 0 or 1
|
||||
|
||||
cvar_t pausable = { "pausable", "1" };
|
||||
|
||||
cvar_t temp1 = { "temp1", "0" };
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Host_EndGame
|
||||
================
|
||||
*/
|
||||
void
|
||||
Host_EndGame(char *message, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
va_start(argptr, message);
|
||||
vsprintf(string, message, argptr);
|
||||
va_end(argptr);
|
||||
Con_DPrintf("%s: %s\n", __func__, string);
|
||||
|
||||
if (sv.active)
|
||||
Host_ShutdownServer(false);
|
||||
|
||||
if (cls.state == ca_dedicated)
|
||||
Sys_Error("%s: %s", __func__, string); // dedicated servers exit
|
||||
|
||||
if (cls.demonum != -1)
|
||||
CL_NextDemo();
|
||||
else
|
||||
CL_Disconnect();
|
||||
|
||||
longjmp(host_abortserver, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Host_Error
|
||||
|
||||
This shuts down both the client and server
|
||||
================
|
||||
*/
|
||||
void
|
||||
Host_Error(char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
static qboolean inerror = false;
|
||||
|
||||
if (inerror)
|
||||
Sys_Error("%s: recursively entered", __func__);
|
||||
inerror = true;
|
||||
|
||||
SCR_EndLoadingPlaque(); // reenable screen updates
|
||||
|
||||
va_start(argptr, error);
|
||||
vsprintf(string, error, argptr);
|
||||
va_end(argptr);
|
||||
Con_Printf("%s: %s\n", __func__, string);
|
||||
|
||||
if (sv.active)
|
||||
Host_ShutdownServer(false);
|
||||
|
||||
if (cls.state == ca_dedicated)
|
||||
Sys_Error("%s: %s", __func__, string); // dedicated servers exit
|
||||
|
||||
CL_Disconnect();
|
||||
cls.demonum = -1;
|
||||
|
||||
inerror = false;
|
||||
|
||||
longjmp(host_abortserver, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Host_FindMaxClients
|
||||
================
|
||||
*/
|
||||
void
|
||||
Host_FindMaxClients(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
svs.maxclients = 1;
|
||||
|
||||
i = COM_CheckParm("-dedicated");
|
||||
if (i) {
|
||||
cls.state = ca_dedicated;
|
||||
if (i != (com_argc - 1)) {
|
||||
svs.maxclients = Q_atoi(com_argv[i + 1]);
|
||||
} else
|
||||
svs.maxclients = 8;
|
||||
} else
|
||||
cls.state = ca_disconnected;
|
||||
|
||||
i = COM_CheckParm("-listen");
|
||||
if (i) {
|
||||
if (cls.state == ca_dedicated)
|
||||
Sys_Error("Only one of -dedicated or -listen can be specified");
|
||||
if (i != (com_argc - 1))
|
||||
svs.maxclients = Q_atoi(com_argv[i + 1]);
|
||||
else
|
||||
svs.maxclients = 8;
|
||||
}
|
||||
if (svs.maxclients < 1)
|
||||
svs.maxclients = 8;
|
||||
else if (svs.maxclients > MAX_SCOREBOARD)
|
||||
svs.maxclients = MAX_SCOREBOARD;
|
||||
|
||||
svs.maxclientslimit = svs.maxclients;
|
||||
if (svs.maxclientslimit < 4)
|
||||
svs.maxclientslimit = 4;
|
||||
svs.clients =
|
||||
Hunk_AllocName(svs.maxclientslimit * sizeof(client_t), "clients");
|
||||
|
||||
if (svs.maxclients > 1)
|
||||
Cvar_SetValue("deathmatch", 1.0);
|
||||
else
|
||||
Cvar_SetValue("deathmatch", 0.0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=======================
|
||||
Host_InitLocal
|
||||
======================
|
||||
*/
|
||||
void
|
||||
Host_InitLocal(void)
|
||||
{
|
||||
Host_InitCommands();
|
||||
|
||||
Cvar_RegisterVariable(&host_framerate);
|
||||
Cvar_RegisterVariable(&host_speeds);
|
||||
|
||||
Cvar_RegisterVariable(&sys_ticrate);
|
||||
Cvar_RegisterVariable(&serverprofile);
|
||||
|
||||
Cvar_RegisterVariable(&fraglimit);
|
||||
Cvar_RegisterVariable(&timelimit);
|
||||
Cvar_RegisterVariable(&teamplay);
|
||||
Cvar_RegisterVariable(&samelevel);
|
||||
Cvar_RegisterVariable(&noexit);
|
||||
Cvar_RegisterVariable(&skill);
|
||||
Cvar_RegisterVariable(&developer);
|
||||
Cvar_RegisterVariable(&deathmatch);
|
||||
Cvar_RegisterVariable(&coop);
|
||||
|
||||
Cvar_RegisterVariable(&pausable);
|
||||
|
||||
Cvar_RegisterVariable(&temp1);
|
||||
|
||||
Host_FindMaxClients();
|
||||
|
||||
host_time = 1.0; // so a think at time 0 won't get called
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Host_WriteConfiguration
|
||||
|
||||
Writes key bindings and archived cvars to config.cfg
|
||||
===============
|
||||
*/
|
||||
void
|
||||
Host_WriteConfiguration(void)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
// dedicated servers initialize the host but don't parse and set the
|
||||
// config.cfg cvars
|
||||
if (host_initialized & !isDedicated) {
|
||||
f = fopen(va("%s/config.cfg", com_gamedir), "w");
|
||||
if (!f) {
|
||||
Con_Printf("Couldn't write config.cfg.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Key_WriteBindings(f);
|
||||
Cvar_WriteVariables(f);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_ClientPrintf
|
||||
|
||||
Sends text across to be displayed
|
||||
FIXME: make this just a stuffed echo?
|
||||
=================
|
||||
*/
|
||||
void
|
||||
SV_ClientPrintf(char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
va_start(argptr, fmt);
|
||||
vsprintf(string, fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
MSG_WriteByte(&host_client->message, svc_print);
|
||||
MSG_WriteString(&host_client->message, string);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_BroadcastPrintf
|
||||
|
||||
Sends text to all active clients
|
||||
=================
|
||||
*/
|
||||
void
|
||||
SV_BroadcastPrintf(char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
int i;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
vsprintf(string, fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
for (i = 0; i < svs.maxclients; i++)
|
||||
if (svs.clients[i].active && svs.clients[i].spawned) {
|
||||
MSG_WriteByte(&svs.clients[i].message, svc_print);
|
||||
MSG_WriteString(&svs.clients[i].message, string);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_ClientCommands
|
||||
|
||||
Send text over to the client to be executed
|
||||
=================
|
||||
*/
|
||||
void
|
||||
Host_ClientCommands(char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
va_start(argptr, fmt);
|
||||
vsprintf(string, fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
MSG_WriteByte(&host_client->message, svc_stufftext);
|
||||
MSG_WriteString(&host_client->message, string);
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
SV_DropClient
|
||||
|
||||
Called when the player is getting totally kicked off the host
|
||||
if (crash = true), don't bother sending signofs
|
||||
=====================
|
||||
*/
|
||||
void
|
||||
SV_DropClient(qboolean crash)
|
||||
{
|
||||
int saveSelf;
|
||||
int i;
|
||||
client_t *client;
|
||||
|
||||
if (!crash) {
|
||||
// send any final messages (don't check for errors)
|
||||
if (NET_CanSendMessage(host_client->netconnection)) {
|
||||
MSG_WriteByte(&host_client->message, svc_disconnect);
|
||||
NET_SendMessage(host_client->netconnection,
|
||||
&host_client->message);
|
||||
}
|
||||
|
||||
if (host_client->edict && host_client->spawned) {
|
||||
// call the prog function for removing a client
|
||||
// this will set the body to a dead frame, among other things
|
||||
saveSelf = pr_global_struct->self;
|
||||
pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
|
||||
PR_ExecuteProgram(pr_global_struct->ClientDisconnect);
|
||||
pr_global_struct->self = saveSelf;
|
||||
}
|
||||
|
||||
Sys_Printf("Client %s removed\n", host_client->name);
|
||||
}
|
||||
// break the net connection
|
||||
NET_Close(host_client->netconnection);
|
||||
host_client->netconnection = NULL;
|
||||
|
||||
// free the client (the body stays around)
|
||||
host_client->active = false;
|
||||
host_client->name[0] = 0;
|
||||
host_client->old_frags = -999999;
|
||||
net_activeconnections--;
|
||||
|
||||
// send notification to all clients
|
||||
for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) {
|
||||
if (!client->active)
|
||||
continue;
|
||||
MSG_WriteByte(&client->message, svc_updatename);
|
||||
MSG_WriteByte(&client->message, host_client - svs.clients);
|
||||
MSG_WriteString(&client->message, "");
|
||||
MSG_WriteByte(&client->message, svc_updatefrags);
|
||||
MSG_WriteByte(&client->message, host_client - svs.clients);
|
||||
MSG_WriteShort(&client->message, 0);
|
||||
MSG_WriteByte(&client->message, svc_updatecolors);
|
||||
MSG_WriteByte(&client->message, host_client - svs.clients);
|
||||
MSG_WriteByte(&client->message, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Host_ShutdownServer
|
||||
|
||||
This only happens at the end of a game, not between levels
|
||||
==================
|
||||
*/
|
||||
void
|
||||
Host_ShutdownServer(qboolean crash)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
sizebuf_t buf;
|
||||
char message[4];
|
||||
double start;
|
||||
|
||||
if (!sv.active)
|
||||
return;
|
||||
|
||||
sv.active = false;
|
||||
|
||||
// stop all client sounds immediately
|
||||
if (cls.state >= ca_connected)
|
||||
CL_Disconnect();
|
||||
|
||||
// flush any pending messages - like the score!!!
|
||||
start = Sys_DoubleTime();
|
||||
do {
|
||||
count = 0;
|
||||
for (i = 0, host_client = svs.clients; i < svs.maxclients;
|
||||
i++, host_client++) {
|
||||
if (host_client->active && host_client->message.cursize) {
|
||||
if (NET_CanSendMessage(host_client->netconnection)) {
|
||||
NET_SendMessage(host_client->netconnection,
|
||||
&host_client->message);
|
||||
SZ_Clear(&host_client->message);
|
||||
} else {
|
||||
NET_GetMessage(host_client->netconnection);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((Sys_DoubleTime() - start) > 3.0)
|
||||
break;
|
||||
}
|
||||
while (count);
|
||||
|
||||
// make sure all the clients know we're disconnecting
|
||||
buf.data = message;
|
||||
buf.maxsize = 4;
|
||||
buf.cursize = 0;
|
||||
MSG_WriteByte(&buf, svc_disconnect);
|
||||
count = NET_SendToAll(&buf, 5);
|
||||
if (count)
|
||||
Con_Printf
|
||||
("Host_ShutdownServer: NET_SendToAll failed for %u clients\n",
|
||||
count);
|
||||
|
||||
for (i = 0, host_client = svs.clients; i < svs.maxclients;
|
||||
i++, host_client++)
|
||||
if (host_client->active)
|
||||
SV_DropClient(crash);
|
||||
|
||||
//
|
||||
// clear structures
|
||||
//
|
||||
memset(&sv, 0, sizeof(sv));
|
||||
memset(svs.clients, 0, svs.maxclientslimit * sizeof(client_t));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Host_ClearMemory
|
||||
|
||||
This clears all the memory used by both the client and server, but does
|
||||
not reinitialize anything.
|
||||
================
|
||||
*/
|
||||
void
|
||||
Host_ClearMemory(void)
|
||||
{
|
||||
Con_DPrintf("Clearing memory\n");
|
||||
D_FlushCaches();
|
||||
Mod_ClearAll();
|
||||
if (host_hunklevel)
|
||||
Hunk_FreeToLowMark(host_hunklevel);
|
||||
|
||||
cls.signon = 0;
|
||||
memset(&sv, 0, sizeof(sv));
|
||||
memset(&cl, 0, sizeof(cl));
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Host_FilterTime
|
||||
|
||||
Returns false if the time is too short to run a frame
|
||||
===================
|
||||
*/
|
||||
qboolean
|
||||
Host_FilterTime(float time)
|
||||
{
|
||||
realtime += time;
|
||||
|
||||
if (!cls.timedemo && realtime - oldrealtime < 1.0 / 72.0)
|
||||
return false; // framerate is too high
|
||||
|
||||
host_frametime = realtime - oldrealtime;
|
||||
oldrealtime = realtime;
|
||||
|
||||
if (host_framerate.value > 0)
|
||||
host_frametime = host_framerate.value;
|
||||
else { // don't allow really long or short frames
|
||||
if (host_frametime > 0.1)
|
||||
host_frametime = 0.1;
|
||||
if (host_frametime < 0.001)
|
||||
host_frametime = 0.001;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Host_GetConsoleCommands
|
||||
|
||||
Add them exactly as if they had been typed at the console
|
||||
===================
|
||||
*/
|
||||
void
|
||||
Host_GetConsoleCommands(void)
|
||||
{
|
||||
char *cmd;
|
||||
|
||||
while (1) {
|
||||
cmd = Sys_ConsoleInput();
|
||||
if (!cmd)
|
||||
break;
|
||||
Cbuf_AddText(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Host_ServerFrame
|
||||
|
||||
==================
|
||||
*/
|
||||
#ifdef FPS_20
|
||||
|
||||
void
|
||||
_Host_ServerFrame(void)
|
||||
{
|
||||
// run the world state
|
||||
pr_global_struct->frametime = host_frametime;
|
||||
|
||||
// read client messages
|
||||
SV_RunClients();
|
||||
|
||||
// move things around and think
|
||||
// always pause in single player if in console or menus
|
||||
if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game))
|
||||
SV_Physics();
|
||||
}
|
||||
|
||||
void
|
||||
Host_ServerFrame(void)
|
||||
{
|
||||
float save_host_frametime;
|
||||
float temp_host_frametime;
|
||||
|
||||
// run the world state
|
||||
pr_global_struct->frametime = host_frametime;
|
||||
|
||||
// set the time and clear the general datagram
|
||||
SV_ClearDatagram();
|
||||
|
||||
// check for new clients
|
||||
SV_CheckForNewClients();
|
||||
|
||||
temp_host_frametime = save_host_frametime = host_frametime;
|
||||
while (temp_host_frametime > (1.0 / 72.0)) {
|
||||
if (temp_host_frametime > 0.05)
|
||||
host_frametime = 0.05;
|
||||
else
|
||||
host_frametime = temp_host_frametime;
|
||||
temp_host_frametime -= host_frametime;
|
||||
_Host_ServerFrame();
|
||||
}
|
||||
host_frametime = save_host_frametime;
|
||||
|
||||
// send all messages to the clients
|
||||
SV_SendClientMessages();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
Host_ServerFrame(void)
|
||||
{
|
||||
/* run the world state */
|
||||
pr_global_struct->frametime = host_frametime;
|
||||
|
||||
/* set the time and clear the general datagram */
|
||||
SV_ClearDatagram();
|
||||
|
||||
/* check for new clients */
|
||||
SV_CheckForNewClients();
|
||||
|
||||
/* read client messages */
|
||||
SV_RunClients();
|
||||
|
||||
/*
|
||||
* Move things around and think. Always pause in single player if in
|
||||
* console or menus
|
||||
*/
|
||||
if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game))
|
||||
SV_Physics();
|
||||
|
||||
/* send all messages to the clients */
|
||||
SV_SendClientMessages();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Host_Frame
|
||||
|
||||
Runs all active servers
|
||||
==================
|
||||
*/
|
||||
void
|
||||
_Host_Frame(float time)
|
||||
{
|
||||
static double time1 = 0;
|
||||
static double time2 = 0;
|
||||
static double time3 = 0;
|
||||
int pass1, pass2, pass3;
|
||||
|
||||
/* something bad happened, or the server disconnected */
|
||||
if (setjmp(host_abortserver))
|
||||
return;
|
||||
|
||||
/* keep the random time dependent */
|
||||
rand();
|
||||
|
||||
/*
|
||||
* Decide the simulation time. Don't run too fast, or packets will flood
|
||||
* out.
|
||||
*/
|
||||
if (!Host_FilterTime(time))
|
||||
return;
|
||||
|
||||
/* get new key events */
|
||||
Sys_SendKeyEvents();
|
||||
|
||||
/* allow mice or other external controllers to add commands */
|
||||
IN_Commands();
|
||||
|
||||
/* process console commands */
|
||||
Cbuf_Execute();
|
||||
|
||||
NET_Poll();
|
||||
|
||||
/* if running the server locally, make intentions now */
|
||||
if (sv.active)
|
||||
CL_SendCmd();
|
||||
|
||||
//-------------------
|
||||
//
|
||||
// server operations
|
||||
//
|
||||
//-------------------
|
||||
|
||||
/* check for commands typed to the host */
|
||||
Host_GetConsoleCommands();
|
||||
|
||||
if (sv.active)
|
||||
Host_ServerFrame();
|
||||
|
||||
//-------------------
|
||||
//
|
||||
// client operations
|
||||
//
|
||||
//-------------------
|
||||
|
||||
/*
|
||||
* if running the server remotely, send intentions now after the incoming
|
||||
* messages have been read
|
||||
*/
|
||||
if (!sv.active)
|
||||
CL_SendCmd();
|
||||
|
||||
host_time += host_frametime;
|
||||
|
||||
/* fetch results from server */
|
||||
if (cls.state >= ca_connected)
|
||||
CL_ReadFromServer();
|
||||
|
||||
/* update video */
|
||||
if (host_speeds.value)
|
||||
time1 = Sys_DoubleTime();
|
||||
|
||||
SCR_UpdateScreen();
|
||||
|
||||
if (host_speeds.value)
|
||||
time2 = Sys_DoubleTime();
|
||||
|
||||
/* update audio */
|
||||
if (cls.state == ca_active) {
|
||||
S_Update(r_origin, vpn, vright, vup);
|
||||
CL_DecayLights();
|
||||
} else
|
||||
S_Update(vec3_origin, vec3_origin, vec3_origin, vec3_origin);
|
||||
|
||||
CDAudio_Update();
|
||||
|
||||
if (host_speeds.value) {
|
||||
pass1 = (time1 - time3) * 1000;
|
||||
time3 = Sys_DoubleTime();
|
||||
pass2 = (time2 - time1) * 1000;
|
||||
pass3 = (time3 - time2) * 1000;
|
||||
Con_Printf("%3i tot %3i server %3i gfx %3i snd\n",
|
||||
pass1 + pass2 + pass3, pass1, pass2, pass3);
|
||||
}
|
||||
|
||||
host_framecount++;
|
||||
}
|
||||
|
||||
void
|
||||
Host_Frame(float time)
|
||||
{
|
||||
double time1, time2;
|
||||
static double timetotal;
|
||||
static int timecount;
|
||||
int i, c, m;
|
||||
|
||||
if (!serverprofile.value) {
|
||||
_Host_Frame(time);
|
||||
return;
|
||||
}
|
||||
|
||||
time1 = Sys_DoubleTime();
|
||||
_Host_Frame(time);
|
||||
time2 = Sys_DoubleTime();
|
||||
|
||||
timetotal += time2 - time1;
|
||||
timecount++;
|
||||
|
||||
if (timecount < 1000)
|
||||
return;
|
||||
|
||||
m = timetotal * 1000 / timecount;
|
||||
timecount = 0;
|
||||
timetotal = 0;
|
||||
c = 0;
|
||||
for (i = 0; i < svs.maxclients; i++) {
|
||||
if (svs.clients[i].active)
|
||||
c++;
|
||||
}
|
||||
|
||||
Con_Printf("serverprofile: %2i clients %2i msec\n", c, m);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
#define VCR_SIGNATURE 0x56435231
|
||||
// "VCR1"
|
||||
|
||||
void
|
||||
Host_InitVCR(quakeparms_t *parms)
|
||||
{
|
||||
int i, len, n;
|
||||
char *p;
|
||||
|
||||
if (COM_CheckParm("-playback")) {
|
||||
if (com_argc != 2)
|
||||
Sys_Error("No other parameters allowed with -playback");
|
||||
|
||||
Sys_FileOpenRead("quake.vcr", &vcrFile);
|
||||
if (vcrFile == -1)
|
||||
Sys_Error("playback file not found");
|
||||
|
||||
Sys_FileRead(vcrFile, &i, sizeof(int));
|
||||
if (i != VCR_SIGNATURE)
|
||||
Sys_Error("Invalid signature in vcr file");
|
||||
|
||||
Sys_FileRead(vcrFile, &com_argc, sizeof(int));
|
||||
com_argv = malloc(com_argc * sizeof(char *));
|
||||
com_argv[0] = parms->argv[0];
|
||||
for (i = 0; i < com_argc; i++) {
|
||||
Sys_FileRead(vcrFile, &len, sizeof(int));
|
||||
p = malloc(len);
|
||||
Sys_FileRead(vcrFile, p, len);
|
||||
com_argv[i + 1] = p;
|
||||
}
|
||||
com_argc++; /* add one for arg[0] */
|
||||
parms->argc = com_argc;
|
||||
parms->argv = com_argv;
|
||||
}
|
||||
|
||||
if ((n = COM_CheckParm("-record")) != 0) {
|
||||
vcrFile = Sys_FileOpenWrite("quake.vcr");
|
||||
|
||||
i = VCR_SIGNATURE;
|
||||
Sys_FileWrite(vcrFile, &i, sizeof(int));
|
||||
i = com_argc - 1;
|
||||
Sys_FileWrite(vcrFile, &i, sizeof(int));
|
||||
for (i = 1; i < com_argc; i++) {
|
||||
if (i == n) {
|
||||
len = 10;
|
||||
Sys_FileWrite(vcrFile, &len, sizeof(int));
|
||||
Sys_FileWrite(vcrFile, "-playback", len);
|
||||
continue;
|
||||
}
|
||||
len = strlen(com_argv[i]) + 1;
|
||||
Sys_FileWrite(vcrFile, &len, sizeof(int));
|
||||
Sys_FileWrite(vcrFile, com_argv[i], len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
Host_Init
|
||||
====================
|
||||
*/
|
||||
void
|
||||
Host_Init(quakeparms_t *parms)
|
||||
{
|
||||
|
||||
if (standard_quake)
|
||||
minimum_memory = MINIMUM_MEMORY;
|
||||
else
|
||||
minimum_memory = MINIMUM_MEMORY_LEVELPAK;
|
||||
|
||||
if (COM_CheckParm("-minmemory"))
|
||||
parms->memsize = minimum_memory;
|
||||
|
||||
host_parms = *parms;
|
||||
|
||||
if (parms->memsize < minimum_memory)
|
||||
Sys_Error("Only %4.1f megs of memory available, can't execute game",
|
||||
parms->memsize / (float)0x100000);
|
||||
|
||||
com_argc = parms->argc;
|
||||
com_argv = parms->argv;
|
||||
|
||||
Memory_Init(parms->membase, parms->memsize);
|
||||
Cbuf_Init();
|
||||
Cmd_Init();
|
||||
V_Init();
|
||||
Chase_Init();
|
||||
Host_InitVCR(parms);
|
||||
COM_Init(parms->basedir);
|
||||
Host_InitLocal();
|
||||
W_LoadWadFile("gfx.wad");
|
||||
Key_Init();
|
||||
Con_Init();
|
||||
M_Init();
|
||||
PR_Init();
|
||||
Mod_Init();
|
||||
NET_Init();
|
||||
SV_Init();
|
||||
|
||||
Con_Printf("Exe: " __TIME__ " " __DATE__ "\n");
|
||||
Con_Printf("%4.1f megabyte heap\n", parms->memsize / (1024 * 1024.0));
|
||||
|
||||
R_InitTextures(); // needed even for dedicated servers
|
||||
|
||||
if (cls.state != ca_dedicated) {
|
||||
host_basepal = (byte *)COM_LoadHunkFile("gfx/palette.lmp");
|
||||
if (!host_basepal)
|
||||
Sys_Error("Couldn't load gfx/palette.lmp");
|
||||
host_colormap = (byte *)COM_LoadHunkFile("gfx/colormap.lmp");
|
||||
if (!host_colormap)
|
||||
Sys_Error("Couldn't load gfx/colormap.lmp");
|
||||
|
||||
#if 0
|
||||
#ifndef _WIN32
|
||||
/*
|
||||
* On non win32, mouse comes before video for security reasons
|
||||
* FIXME - huh?
|
||||
*/
|
||||
IN_Init ();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
VID_Init(host_basepal);
|
||||
|
||||
Draw_Init();
|
||||
SCR_Init();
|
||||
R_Init();
|
||||
|
||||
#ifndef _WIN32
|
||||
/*
|
||||
* On Win32, sound initialization has to come before video
|
||||
* initialization, so we can put up a popup if the sound hardware is
|
||||
* in use
|
||||
*/
|
||||
S_Init();
|
||||
#else
|
||||
|
||||
#ifdef GLQUAKE
|
||||
// FIXME: doesn't use the new one-window approach yet
|
||||
S_Init();
|
||||
#endif
|
||||
|
||||
#endif // _WIN32
|
||||
CDAudio_Init();
|
||||
Sbar_Init();
|
||||
CL_Init();
|
||||
|
||||
//#ifdef _WIN32
|
||||
// on non win32, mouse comes before video for security reasons
|
||||
IN_Init();
|
||||
//#endif
|
||||
}
|
||||
|
||||
Cbuf_InsertText("exec quake.rc\n");
|
||||
|
||||
Hunk_AllocName(0, "-HOST_HUNKLEVEL-");
|
||||
host_hunklevel = Hunk_LowMark();
|
||||
|
||||
host_initialized = true;
|
||||
|
||||
Sys_Printf("========Quake Initialized=========\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Host_Shutdown
|
||||
|
||||
FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better
|
||||
to run quit through here before the final handoff to the sys code.
|
||||
===============
|
||||
*/
|
||||
void
|
||||
Host_Shutdown(void)
|
||||
{
|
||||
static qboolean isdown = false;
|
||||
|
||||
if (isdown) {
|
||||
printf("recursive shutdown\n");
|
||||
return;
|
||||
}
|
||||
isdown = true;
|
||||
|
||||
// keep Con_Printf from trying to update the screen
|
||||
scr_disabled_for_loading = true;
|
||||
|
||||
Host_WriteConfiguration();
|
||||
|
||||
CDAudio_Shutdown();
|
||||
NET_Shutdown();
|
||||
S_Shutdown();
|
||||
IN_Shutdown();
|
||||
|
||||
if (cls.state != ca_dedicated) {
|
||||
VID_Shutdown();
|
||||
}
|
||||
}
|
68
NQ/host.h
Normal file
68
NQ/host.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef HOST_H
|
||||
#define HOST_H
|
||||
|
||||
#include "qtypes.h" /* qboolean */
|
||||
#include "quakedef.h" /* quakeparms_t */
|
||||
|
||||
// FIXME - some of this is out of place or badly named...
|
||||
|
||||
extern quakeparms_t host_parms;
|
||||
|
||||
extern cvar_t sys_ticrate;
|
||||
extern cvar_t sys_nostdout;
|
||||
extern cvar_t developer;
|
||||
|
||||
extern qboolean host_initialized; // true if into command execution
|
||||
extern double host_frametime;
|
||||
extern byte *host_basepal;
|
||||
extern byte *host_colormap;
|
||||
extern int host_framecount; // incremented every frame, never reset
|
||||
extern double realtime; // not bounded in any way, changed at
|
||||
|
||||
// start of every frame, never reset
|
||||
|
||||
void Host_ClearMemory(void);
|
||||
void Host_ServerFrame(void);
|
||||
void Host_InitCommands(void);
|
||||
void Host_Init(quakeparms_t *parms);
|
||||
void Host_Shutdown(void);
|
||||
void Host_Error(char *error, ...);
|
||||
void Host_EndGame(char *message, ...);
|
||||
void Host_Frame(float time);
|
||||
void Host_Quit_f(void);
|
||||
void Host_ClientCommands(char *fmt, ...);
|
||||
void Host_ShutdownServer(qboolean crash);
|
||||
|
||||
extern qboolean msg_suppress_1; // suppresses resolution and cache size console
|
||||
|
||||
// output an fullscreen DIB focus gain/loss
|
||||
extern int current_skill; // skill level for currently loaded level (in
|
||||
|
||||
// case the user changes the cvar while the
|
||||
// level is running, this reflects the level
|
||||
// actually in use)
|
||||
|
||||
extern qboolean isDedicated;
|
||||
|
||||
extern int minimum_memory;
|
||||
|
||||
#endif /* HOST_H */
|
1631
NQ/host_cmd.c
Normal file
1631
NQ/host_cmd.c
Normal file
File diff suppressed because it is too large
Load Diff
279
NQ/kit/3DFX.TXT
Normal file
279
NQ/kit/3DFX.TXT
Normal file
@ -0,0 +1,279 @@
|
||||
GLQuake Drivers for Voodoo Graphics Based 3D Accelerators
|
||||
Preliminary Release 2
|
||||
|
||||
Copyright ( 1997 3Dfx Interactive, Inc. )
|
||||
All Rights Reserved
|
||||
|
||||
3Dfx Interactive, Inc.
|
||||
www: www.3dfx.com
|
||||
news: news.3dfx.com
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
NOTE: GLQuake requires DirectX 2.0 or DirectX 3.0
|
||||
(Needed for DirectSound support)
|
||||
|
||||
DirectX 2.0 or DirectX 3.0 can be installed from the media provided
|
||||
with your Voodoo Based 3D Accelerator.
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
Release Notes for GLQuake Preliminary Release 2 (Quake Version 1.07)
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
What's in the distribution?
|
||||
-----------------------------------------------------------------------
|
||||
This distribution contains GLQuake Drivers for Voodoo Graphics Based 3D
|
||||
Accelerators. These drivers were tested on the following boards:
|
||||
|
||||
- Diamond Monster 3D
|
||||
- Orchid Righteous 3D
|
||||
- 3Dfx Interactive reference boards
|
||||
|
||||
NOTE: The enclosed drivers are not meant to replace any Direct3D or
|
||||
Glide drivers provided by your Voodoo Graphics card manufacturer.
|
||||
Please obtain supported drivers from:
|
||||
|
||||
- Diamond supported drivers can be obtained from www.diamondmm.com
|
||||
- Orchid supported drivers can be obtained from www.orchid.com
|
||||
|
||||
|
||||
Included Files
|
||||
--------------
|
||||
|
||||
OPENGL32.DLL - QuakeGL Interface to Voodoo Graphics
|
||||
FXMEMMAP.VXD - Voodoo Graphics VXD
|
||||
GLQUAKE.EXE - ID Software provided GLQUAKE.EXE
|
||||
README.TXT - ID Software provided README.TXT
|
||||
READ3DFX.TXT - This File
|
||||
|
||||
All enclosed files MUST reside in your Quake directory and not in the
|
||||
Windows\SYSTEM directory.
|
||||
|
||||
OEMSR2 users: Do NOT replace OPENGL32.DLL located in your
|
||||
Windows\SYSTEM directory.
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
Installation
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- Voodoo Graphics Based 3D Accelerator
|
||||
- Windows 95
|
||||
- A PC with a Pentium 90 or higher CPU
|
||||
- 16MB of RAM
|
||||
- 2D Video card set at 16 bit or higher color
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Adding GLQuake Driver Support
|
||||
-----------------------------
|
||||
1) Install the FULL Version (Not the Shareware version!) of Quake.
|
||||
|
||||
2) Copy the GLQUAKE.EXE and other associated files from the GLQuake
|
||||
ZIP file to your Quake Directory. (Use Windows Explorer)
|
||||
|
||||
3) Copy the enclosed OPENGL32.DLL file to your Quake Directory.
|
||||
(Use Windows Explorer) NOTE: DO NOT COPY OPENGL32.DLL to your
|
||||
Windows\SYSTEM directory
|
||||
|
||||
4) Create a Desktop Shortcut for GLQuake: Using the right mouse button
|
||||
drag the GLQUAKE.EXE file from Windows Explorer to the Desktop.
|
||||
When prompted choose "Create Shortcut"
|
||||
|
||||
5) Create an autoexec.cfg file in the ID1\ directory of your quake
|
||||
installation if you do not already have one. Add the line
|
||||
|
||||
gl_playermip "2"
|
||||
|
||||
to the file.
|
||||
|
||||
6) Start GLQuake by running the shortcut.
|
||||
|
||||
|
||||
Troubleshooting and Frequently Asked Questions
|
||||
----------------------------------------------
|
||||
|
||||
1. Will GLQuake work with shareware Quake?
|
||||
|
||||
No, the full registered version of Quake is required.
|
||||
|
||||
|
||||
|
||||
2. Do I need any other drivers to run GLQuake on Voodoo Graphics?
|
||||
|
||||
Just make sure that the FXMEMMAP.VXD file is in your Windows\SYSTEM
|
||||
directory and that DirectX 2.0, DirectX 3.0 or DirectX 3.0a are
|
||||
installed as GLQuake uses DirectSound. The latest version of DirectX
|
||||
can be obtained from:
|
||||
http://www.microsoft.com/mediadev/download/isdk.htm
|
||||
|
||||
|
||||
|
||||
3. I installed GLQuake and try to run the GLQUAKE.EXE file but I get a
|
||||
"no RGB fullscreen modes available" How do I get GLQuake to run?
|
||||
|
||||
Make sure that your 2D video card is set to 16bit color (65K colors,
|
||||
not 16 colors). In addition, do not start GLQuake from a full screen
|
||||
MS-DOS prompt.
|
||||
|
||||
|
||||
|
||||
4. GLQuake comes up for a little while then drops me back to the
|
||||
Windows 95 desktop, what's wrong?
|
||||
|
||||
Your Virtual Memory settings on your system should be increased. Open
|
||||
Control Panel, System - click on the Performance tab and then click on
|
||||
Virtual Memory. Adjust the settings so that the minimum swap file size
|
||||
is 80MB. You may also want to delete all the mesh files - do this by
|
||||
deleting the quake\ID1\glquake directory.
|
||||
|
||||
|
||||
|
||||
5. Why does GLQuake try to connect to my Internet connection whenever
|
||||
it starts?
|
||||
|
||||
GLQuake uses Windows networking. Auto-Dial is likely enabled in your
|
||||
Internet Control Panel or in Internet Explorer Options. Single
|
||||
Player users: To disable Network use in GLQuake and prevent the
|
||||
network connection screen from coming up, add "-nolan" to the
|
||||
GLQUAKE.EXE command line, example:
|
||||
GLQUAKE.EXE -nolan
|
||||
|
||||
|
||||
|
||||
|
||||
6. I have a three button mouse, but I can't use or set the middle
|
||||
button in GLQuake, what's wrong?
|
||||
|
||||
To use a three button mouse with GLQuake, your Windows mouse driver
|
||||
must support three buttons. Use the Logitech PS/2, Serial or Bus
|
||||
driver instead of the Microsoft or Standard PS/2, Serial or Bus driver.
|
||||
Also, make certain that your Mouse control panel sets the middle button
|
||||
to "middle" and not "double click".
|
||||
|
||||
|
||||
|
||||
7. Mouse input seems jumpy, how do I fix that?
|
||||
|
||||
From the console (hit the ~ tilde key), enter m_filter 1 <enter>
|
||||
This option can be added to the AUTOEXEC.CFG file (in the \ID1
|
||||
directory). You may also add this option to the GLQUAKE.EXE command
|
||||
line, example:
|
||||
GLQUAKE.EXE +m_filter 1
|
||||
|
||||
|
||||
|
||||
8. While playing GLQuake the sound stutters, how do I fix it?
|
||||
|
||||
If your sound card does not support DirectSound, you may encounter
|
||||
stuttering sound during game play. Try adding the following value to
|
||||
the CONFIG.CFG file (in the quake\ID1 directory):
|
||||
_snd_mixahead ".14"
|
||||
|
||||
|
||||
|
||||
9. When I hit ALT-TAB or the Windows start button to switch to another
|
||||
application why do I return to a 640x480 display?
|
||||
|
||||
GLQuake by default needs to keep the 2D display at 640x480 while it is
|
||||
running. To return the display to your normal setting you must exit
|
||||
GLQuake. To prevent this, add the following to the GLQUAKE.EXE command
|
||||
line options "+_windowed_mouse 1" and "-window" example:
|
||||
GLQUAKE.EXE +_windowed_mouse 1 -window
|
||||
|
||||
|
||||
|
||||
10. GLQuake multiplayer can't find other games or won't connect.
|
||||
|
||||
GLQuake uses Windows 95 Networking. Verify that the correct networking
|
||||
components are installed and that you can connect to the other machine
|
||||
using File and print sharing or TCP/IP ping. If you are using IPX also
|
||||
make certain that the frame type is the same on all the systems.
|
||||
|
||||
|
||||
|
||||
11. GLQuake multiplayer slows down alot, how do I fix it?
|
||||
|
||||
Add gl_playermip 2 to the AUTOEXEC.CFG file (in the \ID1 directory)
|
||||
You may however add "+gl_playermip 2" to the GLQUAKE.EXE command line,
|
||||
example:
|
||||
GLQUAKE.EXE +gl_playermip 2
|
||||
|
||||
|
||||
|
||||
12. Does the Activision(r) Scourge of Armagon add-on (Mission Pack 1)
|
||||
work with GLQuake?
|
||||
|
||||
Yes, start GLQUAKE.EXE with a "-hipnotic" switch. Example:
|
||||
GLQUAKE.EXE -hipnotic
|
||||
|
||||
|
||||
|
||||
13. Do other 3rd party quake levels work with GLQuake?
|
||||
|
||||
Not all 3rd party levels have been tested, some may not work properly
|
||||
or optimally.
|
||||
|
||||
|
||||
|
||||
14. Will GLQuake use a Voodoo Graphics accelerator under Windows NT?
|
||||
|
||||
The 3Dfx GLQuake drivers currently only work under Windows 95.
|
||||
|
||||
|
||||
|
||||
15. After installing GLQuake the OpenGL screen savers in Windows 95
|
||||
(OEMSR2) don't work. What's wrong?
|
||||
|
||||
The OpenGL Windows 95 screen savers in OEMSR2 will fail if you copied
|
||||
the OPENGL32.DLL file that comes with GLQuake to your Windows\SYSTEM
|
||||
directory. The 3Dfx OPENGL32.DLL file only works with Quake. It will
|
||||
not run with other OpenGL applications. If you copied the 3Dfx
|
||||
OPENGL32.DLL to your Windows\SYSTEM directory and need to restore the
|
||||
Microsoft provided OPENGL32.DLL, follow these steps:
|
||||
|
||||
OEMSR2 Users
|
||||
------------
|
||||
1) Insert your Windows 95 CD into your CD-ROM drive
|
||||
2) Open a MS-DOS prompt, (Click Start, Programs, MS-DOS Prompt)
|
||||
3) Switch to the Windows\SYSTEM directory, ie:
|
||||
C: <enter>
|
||||
CD\Windows\system <enter>
|
||||
4) At the command prompt, enter:
|
||||
EXTRACT /A E:\WIN95 opengl32.dll <enter>
|
||||
(Substitute E:\ for your CD-ROM drive letter)
|
||||
|
||||
Standard Windows 95 Users
|
||||
-------------------------
|
||||
1) Download and reinstall OpenGL for Windows 95 from the source
|
||||
you previously used.
|
||||
|
||||
|
||||
|
||||
16. How do I get support for GLQuake
|
||||
|
||||
GLQuake is currently unsupported. You may however find answers to
|
||||
questions on various Quake dedicated websites. 3Dfx provides a GLQuake
|
||||
newsgroup on news.3dfx.com (Newsgroup name is 3dfx.games.glquake ) to
|
||||
discuss GLQuake with other users. 3Dfx also provides a regularly
|
||||
updated GLQuake FAQ at: http://www.3dfx.com/game_dev/quake_faq.html
|
||||
|
||||
|
||||
|
||||
16. How do I send a bug report?
|
||||
|
||||
If your problem is not resolved in this document or our updated FAQ
|
||||
(please see #15) and your bug is related to visual quality, performance
|
||||
or stability send an email to quake_bugs@3dfx.com - Describe your
|
||||
system configuration (CPU Type, CPU Speed, 2D Video Card type, Amount
|
||||
of Memory, Virtual Memory Size..etc.) and how to recreate the bug.
|
||||
|
||||
|
||||
Voodoo Graphics is a trademark of 3Dfx Interactive, Inc. All other
|
||||
trademarks are the property of their respective owners.
|
167
NQ/kit/JOYSTICK.TXT
Normal file
167
NQ/kit/JOYSTICK.TXT
Normal file
@ -0,0 +1,167 @@
|
||||
|
||||
NEW NOTE FOR 1.08:
|
||||
Joysticks are disabled by defualt now, due to problems on some systems without joysticks installed. Type "joystick 1" at the console, and everything will behave as documented here. This will be saved in your config file, so you will only have to do it once.
|
||||
|
||||
Description of Windows 95 Quake DirectInput support
|
||||
By: FPgaming, Inc. (www.fpgaming.com) -- Creators of the Assassin 3D
|
||||
File: JOYSTICK.TXT
|
||||
Created: 02/21/97
|
||||
(This may be more information than you ever wanted to know.)
|
||||
|
||||
The joystick support with Windows 95 Quake has been significantly enhanced. Standard joysticks, digital joysticks and new advanced controllers like the FPgaming Assassin 3D, the Logitech WingMan Warrior and the SpaceTec IMC SpaceOrb are all supported.
|
||||
|
||||
To make it work, just verify that your joystick or game controller is selected in the Joystick control panel applet and has been calibrated and tested, then launch Windows 95 Quake (WinQuake.exe or glquake.exe). For standard and new digital joysticks, WinQuake will detect the joystick and automatically configure it. For advanced controllers, you will additionally need to run a config file (or run it from your autoexec.cfg) prior to the device operating. This will set the advanced features for your particular device. This config file should be obtained from your game controller company. The config files for the comman game controllers are included below. If you don't want your joystick or game controller enabled, add '-nojoy' to your command-line.
|
||||
|
||||
|
||||
Standard Joystick Support
|
||||
The standard joystick support has been enhanced to provide the following:
|
||||
1. proportional movement (the farther you move the stick, the faster you move)
|
||||
2. support for up to 32 buttons (JOY1-JOY4 and AUX5-AUX32)
|
||||
3. sensitivity setting for each control (allows tuning and inverting the control direction)
|
||||
4. dead-zone setting for each control
|
||||
|
||||
The default joystick setting is for joystick left/right movement to control turning and for joystick forward/backward movement to control moving forward/backward. For optional strafing, add the 'sidestep' feature to one of your buttons (via the Customize menu). For optional looking, add the 'mouse look' feature to one of your buttons (also via the Customize menu).
|
||||
|
||||
Additionally, there are several features that you can set from the Options menu. 'Always Run' allows you change your maximum speed from walking to running. 'Invert Mouse' allows you to change the direction the joystick has to move to when looking up and down. 'Lookspring' enables automatic look-forward-when-moving. And, 'Lookstrafe' automatically enables strafing when the 'mouse look' button is pressed.
|
||||
|
||||
The following variables control your sensititivity settings:
|
||||
joyforwardsensitivity - controls the ramp-up speed for moving forward and backward
|
||||
joysidesensitivity - controls the ramp-up speed for moving side to side
|
||||
joypitchsensitivity - controls the speed that you look up and down
|
||||
joyyawsensitivity - controls the speed that you look left to right
|
||||
You can set the sensitivity settings to negative numbers. This inverts the direction of movement for the control. The default sensitivity settings are 1 (or -1). There is no limit on the range; whatever feels good.
|
||||
|
||||
The following variables control your threshold settings:
|
||||
joyforwardthreshold - controls the dead-zone for moving forward and backward
|
||||
joysidethreshold - controls the dead-zone for moving side to side
|
||||
joypitchthreshold - controls the dead-zone for looking up and down
|
||||
joyyawthreshold - controls the dead-zone for looking left and right
|
||||
The threshold settings allow you to control your dead-zone (or no-movement zone). The default threshold settings are .15 (meaning 15% of the full-range). The range of the threshold settings is from 0 to 1. Troublesome analog joysticks may need a larger number (like .2). Premium joysticks can use a smaller number (like .1).
|
||||
|
||||
The joystick sensitivity settings and the threshold settings are not saved after you quit your game as inadvertant settings can really hose your control. If you want to keep any changes, add them into your autoexec.cfg file.
|
||||
|
||||
If your joystick has a POV hat, the buttons are mapped to AUX29-AUX32. So, you get 8 buttons with the Logitech WingMan Extreme and 12 buttons with the Microsoft SideWinder 3D Pro, etc.
|
||||
|
||||
|
||||
Advanced Controller Support
|
||||
The following features have been added:
|
||||
1. support for all 6 axes (X, Y, Z, R, U, V)
|
||||
2. mapping of any axis to any control (Forward, Look, Side, Turn)
|
||||
3. proportional movement for all controls
|
||||
4. sensitivity setting for any control (allows tuning and inverting the control direction)
|
||||
5. threshold setting for any control (allows dead-zone setting)
|
||||
6. support for absolute controls (like joysticks) and relative controls (like trackballs and spinners)
|
||||
7. support for up to 32 buttons (JOY1-JOY4 and AUX5-AUX32)
|
||||
|
||||
To make an advanced controller operate, you will need to get a config file from your game controller company. This file is typically placed in your quake\id1 directory and then it is called within your autoexec.cfg file. For example, if your config file is named gamectrl.cfg, place that file within your quake\id1 directory and add 'exec gamectrl.cfg' in your autoexec.cfg file. If you don't have an autoexec.cfg file, you can create one and just place this one line in it.
|
||||
|
||||
******************************************************************************
|
||||
NOTE: The information below is for game controller companies to integrate their device and for anyone wanting to create a custom setup.
|
||||
|
||||
In addition to the above new variables, there are six more for axis mapping. These are:
|
||||
joyadvaxisx - controls mapping of DirectInput axis X (typically joystick left and right)
|
||||
joyadvaxisy - controls mapping of DirectInput axis Y (typically joystick forward and backward)
|
||||
joyadvaxisz - controls mapping of DirectInput axis Z (typically joystick throttle)
|
||||
joyadvaxisr - controls mapping of DirectInput axis R (typically joystick rudder)
|
||||
joyadvaxisu - controls mapping of DirectInput axis U (custom axis - Assassin 3D trackball left and right, WingMan Warrior SpinControl and SpaceOrb roll)
|
||||
joyadvaxisv - controls mapping of DirectInput axis V (custom axis - Assassin 3D trackball forward and backward and SpaceOrb yaw)
|
||||
Each joyadvaxis variable can be set to the following controls:
|
||||
0 = Axis not used
|
||||
1 = Axis is for forward and backward movement
|
||||
2 = Axis is for looking up and down (pitch)
|
||||
3 = Axis is for side to side movement
|
||||
4 = Axis is for turning left and right (yaw)
|
||||
Additionally, each axis can be designated as an absolute axis (like a joystick) or a relative axis (like the FPgaming trackball or the WingMan Warrior SpinControl). Absolute axes are defined as having a stopping position whereas relative axes don't have a stopping position and just go around and around. To designate an axis as a relative axis, add 16 to the above control number. For example, to set the Assassin 3D's axis U to be looking left and right, type 'joyadvaxisu 20'. As another example, to make your rudder pedals contol turning left and right, type 'joyadvaxisr 4'. It's a bit complicated, but only needs to be done once.
|
||||
|
||||
The advanced axes variables will not have any effect until joyadvanced is set to 1.0. Additionally, any changes to the to the axes will not take effect until the joyadvancedupdate command is executed. So, the procedure for creating an advanced mapping is:
|
||||
1. set 'joyadvanced 1'
|
||||
2. make any desired mapping changes
|
||||
3. make any desired sensitivity changes
|
||||
4. make any desired threshold changes
|
||||
3. call 'joyadvancedupdate'
|
||||
|
||||
Here is the config file for the FPgaming Assassin 3D:
|
||||
// ADVA3D.CFG
|
||||
// Revision 1.0 -- refer to www.fpgaming.com for updates
|
||||
joyname "FPgaming Assassin 3D"
|
||||
joyadvanced 1
|
||||
joyadvaxisx 3
|
||||
joyadvaxisy 1
|
||||
joyadvaxisz 0
|
||||
joyadvaxisr 0
|
||||
joyadvaxisu 20
|
||||
joyadvaxisv 18
|
||||
joyforwardsensitivity -1.0
|
||||
joysidesensitivity 1.0
|
||||
joypitchsensitivity -0.25
|
||||
joyyawsensitivity -0.5
|
||||
joyforwardthreshold 0.15
|
||||
joysidethreshold 0.15
|
||||
joyyawthreshold 0.0
|
||||
joypitchthreshold 0.0
|
||||
+mlook
|
||||
joyadvancedupdate
|
||||
|
||||
Here is a config file for the Logitech WingMan Warrior:
|
||||
// ADVWW.CFG
|
||||
// Revision 0.1 -- refer to www.logitech.com for updates
|
||||
joyname "Logitech WingMan Warrior"
|
||||
joyadvanced 1.0
|
||||
joywwhack1 1.0
|
||||
joywwhack2 1.0
|
||||
joyadvaxisx 3
|
||||
joyadvaxisy 1
|
||||
joyadvaxisz 0
|
||||
joyadvaxisr 0
|
||||
joyadvaxisu 20
|
||||
joyadvaxisv 0
|
||||
joyforwardsensitivity -1.0
|
||||
joysidesensitivity 1.0
|
||||
joypitchsensitivity 0.0
|
||||
joyyawsensitivity -0.6
|
||||
joyforwardthreshold 0.15
|
||||
joysidethreshold 0.15
|
||||
joypitchthreshold 0.0
|
||||
joyyawthreshold 0.0
|
||||
joyadvancedupdate
|
||||
|
||||
Here is a config file for the SpaceTec IMC SpaceOrb:
|
||||
// ADVSPORB.CFG
|
||||
// Revision 0.1 -- refer to www.spacetec.com for updates
|
||||
joyname "SpaceTec IMC SpaceOrb"
|
||||
joyadvanced 1.0
|
||||
joyadvaxisx 3
|
||||
joyadvaxisy 1
|
||||
joyadvaxisz 0
|
||||
joyadvaxisr 2
|
||||
joyadvaxisu 0
|
||||
joyadvaxisv 4
|
||||
joyforwardsensitivity -1.0
|
||||
joysidesensitivity 1.0
|
||||
joypitchsensitivity -0.5
|
||||
joyyawsensitivity 1
|
||||
joyforwardthreshold 0.1
|
||||
joysidethreshold 0.1
|
||||
joypitchthreshold 0.1
|
||||
joyyawthreshold 0.1
|
||||
+mlook
|
||||
joyadvancedupdate
|
||||
|
||||
Here is a config file for making your joystick operate looking around and strafing, your rudder pedals control turning left and right and throttle control moving forward and backward:
|
||||
joyname "Joystick, Rudder & Throttle"
|
||||
joyadvanced 1.0
|
||||
joyadvaxisx 3
|
||||
joyadvaxisy 2
|
||||
joyadvaxisz 1
|
||||
joyadvaxisr 4
|
||||
joyadvaxisu 0
|
||||
joyadvaxisv 0
|
||||
joyforwardsensitivity -1.0
|
||||
joysidesensitivity -1.0
|
||||
joypitchsensitivity 1.0
|
||||
joyyawsensitivity -1.0
|
||||
joyforwardthreshold 0.15
|
||||
joysidethreshold 0.15
|
||||
joyyawthreshold 0.15
|
||||
joypitchthreshold 0.15
|
||||
joyadvancedupdate
|
171
NQ/kit/README.TXT
Normal file
171
NQ/kit/README.TXT
Normal file
@ -0,0 +1,171 @@
|
||||
Glquake v0.97, Quake v1.09 release notes
|
||||
|
||||
3dfx owners -- read the 3dfx.txt file.
|
||||
|
||||
On a standard OpenGL system, all you should need to do to run glquake is put
|
||||
glquake.exe in your quake directory, and run it from there. DO NOT install
|
||||
the opengl32.dll unless you have a 3dfx! Glquake should change the screen
|
||||
resolution to 640*480*32k colors and run full screen by default.
|
||||
|
||||
If you are running win-95, your desktop must be set to 32k or 64k colors
|
||||
before running glquake. NT can switch automatically.
|
||||
|
||||
Theoretically, glquake will run on any compliant OpenGL that supports the
|
||||
texture objects extensions, but unless it is very powerfull hardware that
|
||||
accelerates everything needed, the game play will not be acceptable. If it
|
||||
has to go through any software emulation paths, the performance will likely
|
||||
by well under one frame per second.
|
||||
|
||||
3dfx has provided an opengl32.dll that implements everything glquake needs,
|
||||
but it is not a full opengl implementation. Other opengl applications are
|
||||
very unlikely to work with it, so consider it basically a "glquake driver".
|
||||
See the encluded 3dfx.txt for specific instalation notes. 3dfx can only run
|
||||
full screen, but you must still have your desktop set to a 16 bit color mode
|
||||
for glquake to start.
|
||||
|
||||
resolution options
|
||||
------------------
|
||||
We had dynamic resolution changing in glquake for a while, but every single
|
||||
opengl driver I tried it on messed up in one way or another, so it is now
|
||||
limited to startup time only.
|
||||
|
||||
glquake -window
|
||||
This will start glquake in a window on your desktop instead of switching the
|
||||
screen to lower resolution and covering everything.
|
||||
|
||||
glquake -width 800 -height 600
|
||||
Tries to run glquake at the specified resolution. Combined with -window, it
|
||||
creates a desktop window that size, otherwise it tries to set a full screen
|
||||
resolution.
|
||||
|
||||
You can also specify the resolution of the console independant of the screen
|
||||
resolution.
|
||||
|
||||
glquake -conwidth 320
|
||||
This will specify a console resolution of 320 by 240 (the height is
|
||||
automatically determined by the default 4:3 aspect ratio, you can also
|
||||
specify the height directly with -conheight).
|
||||
|
||||
In higher resolution modes such as 800x600 and 1024x768, glquake will default
|
||||
to a 640x480 console, since the font becomes small enough at higher
|
||||
resolutions to become unreadable. If do you wish to have a higher resolution
|
||||
console and status bar, specify it as well, such as:
|
||||
glquake -width 800 -height 600 -conwidth 800
|
||||
|
||||
texture options
|
||||
---------------
|
||||
The amount of textures used in the game can have a large impact on performance.
|
||||
There are several options that let you trade off visual quality for better
|
||||
performance.
|
||||
|
||||
There is no way to flush already loaded textures, so it is best to change
|
||||
these options on the command line, or they will only take effect on some of
|
||||
the textures when you change levels.
|
||||
|
||||
OpenGL only allows textures to repeat on power of two boundaries (32, 64,
|
||||
128, etc), but software quake had a number of textures that repeated at 24
|
||||
or 96 pixel boundaries. These need to be either stretched out to the next
|
||||
higher size, or shrunk down to the next lower. By default, they are filtered
|
||||
down to the smaller size, but you can cause it to use the larger size if you
|
||||
really want by using:
|
||||
|
||||
glquake +gl_round_down 0
|
||||
This will generally run well on a normal 4 MB 3dfx card, but for other cards
|
||||
that have either worse texture management or slower texture swapping speeds,
|
||||
there are some additional settings that can drastically lower the amount of
|
||||
textures to be managed.
|
||||
|
||||
glquake +gl_picmip 1
|
||||
This causes all textures to have one half the dimensions they otherwise would.
|
||||
This makes them blurry, but very small. You can set this to 2 to make the
|
||||
textures one quarter the resolution on each axis for REALLY blurry textures.
|
||||
|
||||
glquake +gl_playermip 1
|
||||
This is similar to picmip, but is only used for other players in deathmatch.
|
||||
Each player in a deathmatch requires an individual skin texture, so this can
|
||||
be a serious problem for texture management. It wouldn't be unreasonable to
|
||||
set this to 2 or even 3 if you are playing competatively (and don't care if
|
||||
the other guys have smudged skins). If you change this during the game, it
|
||||
will take effect as soon as a player changes their skin colors.
|
||||
|
||||
GLQuake also supports the following extensions for faster texture operation:
|
||||
|
||||
GL_SGIS_multitexture
|
||||
Multitextures support allows certain hardware to render the world in one
|
||||
pass instead of two. GLQuake uses two passes, one for the world textures
|
||||
and the second for the lightmaps that are blended on the textures. On some
|
||||
hardware, with a GL_SIGS_multitexture supported OpenGL implementation, this
|
||||
can be done in one pass. On hardware that supports this, you will get a
|
||||
60% to 100% increase in frame rate. Currently, only 3DFX dual TMU cards
|
||||
(such as the Obsidian 2220) support this extension, but other hardware will
|
||||
soon follow.
|
||||
|
||||
This extension will be autodetected and used. If for some reason it is not
|
||||
working correctly, specify the command line option "-nomtex" to disable it.
|
||||
|
||||
GL_EXT_shared_texture_palette
|
||||
GLQuake uses 16bit textures by default but on OpenGL implementations
|
||||
that support the GL_EXT_shared_texture_palette extension, GLQuake will use
|
||||
8bit textures instead. This results in using half the needed texture memory
|
||||
of 16bit texture and can improve performance. This is very little difference
|
||||
in visual quality due to the fact that the textures are 8bit sources to
|
||||
begin with.
|
||||
|
||||
run time options
|
||||
----------------
|
||||
At the console, you can set these values to effect drawing.
|
||||
|
||||
gl_texturemode GL_NEAREST
|
||||
Sets texture mapping to point sampled, which may be faster on some GL systems
|
||||
(not on 3dfx).
|
||||
|
||||
gl_texturemode GL_LINEAR_MIPMAP
|
||||
This is the default texture mode.
|
||||
|
||||
gl_texturemode GL_LINEAR_MIPMAP_LINEAR
|
||||
This is the highest quality texture mapping (trilinear), but only very high
|
||||
end hardware (intergraph intense 3D / realizm) supports it. Not that big of
|
||||
a deal, actually.
|
||||
|
||||
gl_finish 0
|
||||
This causes the game to not issue a glFinish() call each frame, which may make
|
||||
some hardware run faster. If this is cleared, the 3dfx will back up a number
|
||||
of frames and not be very playable.
|
||||
|
||||
gl_flashblend 0
|
||||
By default, glquake just draws a shaded ball around objects that are emiting
|
||||
light. Clearing this variable will cause it to properly relight the world
|
||||
like normal quake, but it can be a significant speed hit on some systems.
|
||||
|
||||
gl_ztrick 0
|
||||
Glquake uses a buffering method that avoids clearing the Z buffer, but some
|
||||
hardware platforms don't like it. If the status bar and console are flashing
|
||||
every other frame, clear this variable.
|
||||
|
||||
gl_keeptjunctions 0
|
||||
If you clear this, glquake will remove colinear vertexes when it reloads the
|
||||
level. This can give a few percent speedup, but it can leave a couple stray
|
||||
blinking pixels on the screen.
|
||||
|
||||
novelty features
|
||||
----------------
|
||||
These are some rendering tricks that were easy to do in glquake. They aren't
|
||||
very robust, but they are pretty cool to look at.
|
||||
|
||||
r_shadows 1
|
||||
This causes every object to cast a shadow.
|
||||
|
||||
r_wateralpha 0.7
|
||||
This sets the opacity of water textures, so you can see through it in properly
|
||||
processed maps. 0.3 is very faint, almost like fog. 1 is completely solid
|
||||
(the default). Unfortunately, the standard quake maps don't contain any
|
||||
visibility information for seeing past water surfaces, so you can't just play
|
||||
quake with this turned on. If you just want to see what it looks like, you
|
||||
can set "r_novis 1", but that will make things go very slow. When I get a
|
||||
chance, I will probably release some maps that have been processed properly
|
||||
for this.
|
||||
|
||||
r_mirroralpha 0.3
|
||||
This changes one particular texture (the stained glass texture in the EASY
|
||||
start hall) into a mirror. The value is the opacity of the mirror surface.
|
||||
|
64
NQ/menu.h
Normal file
64
NQ/menu.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MENU_H
|
||||
#define MENU_H
|
||||
|
||||
#include "wad.h"
|
||||
|
||||
//
|
||||
// the net drivers should just set the apropriate bits in m_activenet,
|
||||
// instead of having the menu code look through their internal tables
|
||||
//
|
||||
#define MNET_IPX 1
|
||||
#define MNET_TCP 2
|
||||
|
||||
extern int m_activenet;
|
||||
|
||||
//
|
||||
// menus
|
||||
//
|
||||
void M_Init(void);
|
||||
void M_Keydown(int key);
|
||||
void M_Draw(void);
|
||||
|
||||
void M_ToggleMenu_f(void);
|
||||
void M_Menu_Options_f(void);
|
||||
void M_Menu_Quit_f(void);
|
||||
|
||||
void M_DrawPic(int x, int y, const qpic_t *pic);
|
||||
void M_DrawTransPic(int x, int y, const qpic_t *pic);
|
||||
void M_DrawCharacter(int cx, int line, int num);
|
||||
void M_DrawTextBox(int x, int y, int width, int lines);
|
||||
void M_Print(int cx, int cy, const char *str);
|
||||
void M_PrintWhite(int cx, int cy, const char *str);
|
||||
|
||||
/* FIXME - These are only here for NQ/net_dgrm.c */
|
||||
extern qboolean m_return_onerror;
|
||||
extern char m_return_reason[32];
|
||||
extern int m_return_state;
|
||||
enum {
|
||||
m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup,
|
||||
m_net, m_options, m_video, m_keys, m_help, m_quit, m_serialconfig,
|
||||
m_modemconfig, m_lanconfig, m_gameoptions, m_search,
|
||||
m_slist
|
||||
} m_state;
|
||||
|
||||
#endif /* MENU_H */
|
1827
NQ/model.c
Normal file
1827
NQ/model.c
Normal file
File diff suppressed because it is too large
Load Diff
370
NQ/model.h
Normal file
370
NQ/model.h
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include "bspfile.h"
|
||||
#include "modelgen.h"
|
||||
#include "render.h"
|
||||
#include "spritegn.h"
|
||||
#include "zone.h"
|
||||
|
||||
/*
|
||||
|
||||
d*_t structures are on-disk representations
|
||||
m*_t structures are in-memory
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
BRUSH MODELS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// in memory representation
|
||||
//
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct {
|
||||
vec3_t position;
|
||||
} mvertex_t;
|
||||
|
||||
#define SIDE_FRONT 0
|
||||
#define SIDE_BACK 1
|
||||
#define SIDE_ON 2
|
||||
|
||||
|
||||
// plane_t structure
|
||||
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
||||
typedef struct mplane_s {
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
byte type; // for texture axis selection and fast side tests
|
||||
byte signbits; // signx + signy<<1 + signz<<1
|
||||
byte pad[2];
|
||||
} mplane_t;
|
||||
|
||||
typedef struct texture_s {
|
||||
char name[16];
|
||||
unsigned width, height;
|
||||
int anim_total; // total tenths in sequence ( 0 = no)
|
||||
int anim_min, anim_max; // time for this frame min <=time< max
|
||||
struct texture_s *anim_next; // in the animation sequence
|
||||
struct texture_s *alternate_anims; // bmodels in frmae 1 use these
|
||||
unsigned offsets[MIPLEVELS]; // four mip maps stored
|
||||
} texture_t;
|
||||
|
||||
|
||||
#define SURF_PLANEBACK 2
|
||||
#define SURF_DRAWSKY 4
|
||||
#define SURF_DRAWSPRITE 8
|
||||
#define SURF_DRAWTURB 0x10
|
||||
#define SURF_DRAWTILED 0x20
|
||||
#define SURF_DRAWBACKGROUND 0x40
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct {
|
||||
unsigned short v[2];
|
||||
unsigned int cachededgeoffset;
|
||||
} medge_t;
|
||||
|
||||
typedef struct {
|
||||
float vecs[2][4];
|
||||
float mipadjust;
|
||||
texture_t *texture;
|
||||
int flags;
|
||||
} mtexinfo_t;
|
||||
|
||||
typedef struct msurface_s {
|
||||
int visframe; // should be drawn when node is crossed
|
||||
|
||||
int dlightframe;
|
||||
unsigned dlightbits;
|
||||
|
||||
mplane_t *plane;
|
||||
int flags;
|
||||
|
||||
int firstedge; // look up in model->surfedges[], negative numbers
|
||||
int numedges; // are backwards edges
|
||||
|
||||
// surface generation data
|
||||
struct surfcache_s *cachespots[MIPLEVELS];
|
||||
|
||||
short texturemins[2];
|
||||
short extents[2];
|
||||
|
||||
mtexinfo_t *texinfo;
|
||||
|
||||
// lighting info
|
||||
byte styles[MAXLIGHTMAPS];
|
||||
byte *samples; // [numstyles*surfsize]
|
||||
} msurface_t;
|
||||
|
||||
typedef struct mnode_s {
|
||||
// common with leaf
|
||||
int contents; // 0, to differentiate from leafs
|
||||
int visframe; // node needs to be traversed if current
|
||||
|
||||
short minmaxs[6]; // for bounding box culling
|
||||
|
||||
struct mnode_s *parent;
|
||||
|
||||
// node specific
|
||||
mplane_t *plane;
|
||||
struct mnode_s *children[2];
|
||||
|
||||
unsigned short firstsurface;
|
||||
unsigned short numsurfaces;
|
||||
} mnode_t;
|
||||
|
||||
|
||||
|
||||
typedef struct mleaf_s {
|
||||
// common with node
|
||||
int contents; // wil be a negative contents number
|
||||
int visframe; // node needs to be traversed if current
|
||||
|
||||
short minmaxs[6]; // for bounding box culling
|
||||
|
||||
struct mnode_s *parent;
|
||||
|
||||
// leaf specific
|
||||
byte *compressed_vis;
|
||||
efrag_t *efrags;
|
||||
|
||||
msurface_t **firstmarksurface;
|
||||
int nummarksurfaces;
|
||||
int key; // BSP sequence number for leaf's contents
|
||||
byte ambient_sound_level[NUM_AMBIENTS];
|
||||
} mleaf_t;
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
||||
typedef struct {
|
||||
dclipnode_t *clipnodes;
|
||||
mplane_t *planes;
|
||||
int firstclipnode;
|
||||
int lastclipnode;
|
||||
vec3_t clip_mins;
|
||||
vec3_t clip_maxs;
|
||||
} hull_t;
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
SPRITE MODELS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
// FIXME: shorten these?
|
||||
typedef struct mspriteframe_s {
|
||||
int width;
|
||||
int height;
|
||||
void *pcachespot; // remove?
|
||||
float up, down, left, right;
|
||||
byte pixels[4];
|
||||
} mspriteframe_t;
|
||||
|
||||
typedef struct {
|
||||
int numframes;
|
||||
float *intervals;
|
||||
mspriteframe_t *frames[1];
|
||||
} mspritegroup_t;
|
||||
|
||||
typedef struct {
|
||||
spriteframetype_t type;
|
||||
mspriteframe_t *frameptr;
|
||||
} mspriteframedesc_t;
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
int maxwidth;
|
||||
int maxheight;
|
||||
int numframes;
|
||||
float beamlength; // remove?
|
||||
void *cachespot; // remove?
|
||||
mspriteframedesc_t frames[1];
|
||||
} msprite_t;
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
ALIAS MODELS
|
||||
|
||||
Alias models are position independent, so the cache manager can move them.
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
aliasframetype_t type;
|
||||
trivertx_t bboxmin;
|
||||
trivertx_t bboxmax;
|
||||
int frame;
|
||||
char name[16];
|
||||
} maliasframedesc_t;
|
||||
|
||||
typedef struct {
|
||||
aliasskintype_t type;
|
||||
void *pcachespot;
|
||||
int skin;
|
||||
} maliasskindesc_t;
|
||||
|
||||
typedef struct {
|
||||
trivertx_t bboxmin;
|
||||
trivertx_t bboxmax;
|
||||
int frame;
|
||||
} maliasgroupframedesc_t;
|
||||
|
||||
typedef struct {
|
||||
int numframes;
|
||||
int intervals;
|
||||
maliasgroupframedesc_t frames[1];
|
||||
} maliasgroup_t;
|
||||
|
||||
typedef struct {
|
||||
int numskins;
|
||||
int intervals;
|
||||
maliasskindesc_t skindescs[1];
|
||||
} maliasskingroup_t;
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct mtriangle_s {
|
||||
int facesfront;
|
||||
int vertindex[3];
|
||||
} mtriangle_t;
|
||||
|
||||
typedef struct {
|
||||
int model;
|
||||
int stverts;
|
||||
int skindesc;
|
||||
int triangles;
|
||||
maliasframedesc_t frames[1];
|
||||
} aliashdr_t;
|
||||
|
||||
//===================================================================
|
||||
|
||||
//
|
||||
// Whole model
|
||||
//
|
||||
|
||||
typedef enum { mod_brush, mod_sprite, mod_alias } modtype_t;
|
||||
|
||||
#define EF_ROCKET 1 // leave a trail
|
||||
#define EF_GRENADE 2 // leave a trail
|
||||
#define EF_GIB 4 // leave a trail
|
||||
#define EF_ROTATE 8 // rotate (bonus items)
|
||||
#define EF_TRACER 16 // green split trail
|
||||
#define EF_ZOMGIB 32 // small blood trail
|
||||
#define EF_TRACER2 64 // orange split trail + rotate
|
||||
#define EF_TRACER3 128 // purple trail
|
||||
|
||||
typedef struct model_s {
|
||||
char name[MAX_QPATH];
|
||||
qboolean needload; // bmodels and sprites don't cache normally
|
||||
|
||||
modtype_t type;
|
||||
int numframes;
|
||||
synctype_t synctype;
|
||||
|
||||
int flags;
|
||||
|
||||
//
|
||||
// volume occupied by the model graphics
|
||||
//
|
||||
vec3_t mins, maxs;
|
||||
float radius;
|
||||
|
||||
//
|
||||
// brush model
|
||||
//
|
||||
int firstmodelsurface, nummodelsurfaces;
|
||||
|
||||
int numsubmodels;
|
||||
dmodel_t *submodels;
|
||||
|
||||
int numplanes;
|
||||
mplane_t *planes;
|
||||
|
||||
int numleafs; // number of visible leafs, not counting 0
|
||||
mleaf_t *leafs;
|
||||
|
||||
int numvertexes;
|
||||
mvertex_t *vertexes;
|
||||
|
||||
int numedges;
|
||||
medge_t *edges;
|
||||
|
||||
int numnodes;
|
||||
mnode_t *nodes;
|
||||
|
||||
int numtexinfo;
|
||||
mtexinfo_t *texinfo;
|
||||
|
||||
int numsurfaces;
|
||||
msurface_t *surfaces;
|
||||
|
||||
int numsurfedges;
|
||||
int *surfedges;
|
||||
|
||||
int numclipnodes;
|
||||
dclipnode_t *clipnodes;
|
||||
|
||||
int nummarksurfaces;
|
||||
msurface_t **marksurfaces;
|
||||
|
||||
hull_t hulls[MAX_MAP_HULLS];
|
||||
|
||||
int numtextures;
|
||||
texture_t **textures;
|
||||
|
||||
byte *visdata;
|
||||
byte *lightdata;
|
||||
char *entities;
|
||||
|
||||
//
|
||||
// additional model data
|
||||
//
|
||||
cache_user_t cache; // only access through Mod_Extradata
|
||||
|
||||
} model_t;
|
||||
|
||||
//============================================================================
|
||||
|
||||
void Mod_Init(void);
|
||||
void Mod_ClearAll(void);
|
||||
model_t *Mod_ForName(char *name, qboolean crash);
|
||||
void *Mod_Extradata(model_t *mod); // handles caching
|
||||
void Mod_TouchModel(char *name);
|
||||
void Mod_Print(void);
|
||||
|
||||
mleaf_t *Mod_PointInLeaf(float *p, model_t *model);
|
||||
byte *Mod_LeafPVS(mleaf_t *leaf, model_t *model);
|
||||
|
||||
// FIXME - surely this doesn't belong here?
|
||||
texture_t *R_TextureAnimation(texture_t *base);
|
||||
|
||||
#endif /* MODEL_H */
|
138
NQ/modelgen.h
Normal file
138
NQ/modelgen.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MODELGEN_H
|
||||
#define MODELGEN_H
|
||||
|
||||
//
|
||||
// modelgen.h: header file for model generation program
|
||||
//
|
||||
|
||||
// *********************************************************
|
||||
// * This file must be identical in the modelgen directory *
|
||||
// * and in the Quake directory, because it's used to *
|
||||
// * pass data from one to the other via model files. *
|
||||
// *********************************************************
|
||||
|
||||
// FIXME - check modelgen for INCLUDELIBS (it's not in the engine...)
|
||||
//#ifdef INCLUDELIBS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "host.h"
|
||||
#include "mathlib.h"
|
||||
#include "qtypes.h"
|
||||
|
||||
//#endif
|
||||
|
||||
#define ALIAS_VERSION 6
|
||||
|
||||
#define ALIAS_ONSEAM 0x0020
|
||||
|
||||
// must match definition in spritegn.h
|
||||
#ifndef SYNCTYPE_T
|
||||
#define SYNCTYPE_T
|
||||
typedef enum { ST_SYNC = 0, ST_RAND } synctype_t;
|
||||
#endif
|
||||
|
||||
typedef enum { ALIAS_SINGLE = 0, ALIAS_GROUP } aliasframetype_t;
|
||||
|
||||
typedef enum { ALIAS_SKIN_SINGLE = 0, ALIAS_SKIN_GROUP } aliasskintype_t;
|
||||
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
vec3_t scale;
|
||||
vec3_t scale_origin;
|
||||
float boundingradius;
|
||||
vec3_t eyeposition;
|
||||
int numskins;
|
||||
int skinwidth;
|
||||
int skinheight;
|
||||
int numverts;
|
||||
int numtris;
|
||||
int numframes;
|
||||
synctype_t synctype;
|
||||
int flags;
|
||||
float size;
|
||||
} mdl_t;
|
||||
|
||||
// TODO: could be shorts
|
||||
|
||||
typedef struct {
|
||||
int onseam;
|
||||
int s;
|
||||
int t;
|
||||
} stvert_t;
|
||||
|
||||
typedef struct dtriangle_s {
|
||||
int facesfront;
|
||||
int vertindex[3];
|
||||
} dtriangle_t;
|
||||
|
||||
#define DT_FACES_FRONT 0x0010
|
||||
|
||||
// This mirrors trivert_t in trilib.h, is present so Quake knows how to
|
||||
// load this data
|
||||
|
||||
typedef struct {
|
||||
byte v[3];
|
||||
byte lightnormalindex;
|
||||
} trivertx_t;
|
||||
|
||||
typedef struct {
|
||||
trivertx_t bboxmin; // lightnormal isn't used
|
||||
trivertx_t bboxmax; // lightnormal isn't used
|
||||
char name[16]; // frame name from grabbing
|
||||
} daliasframe_t;
|
||||
|
||||
typedef struct {
|
||||
int numframes;
|
||||
trivertx_t bboxmin; // lightnormal isn't used
|
||||
trivertx_t bboxmax; // lightnormal isn't used
|
||||
} daliasgroup_t;
|
||||
|
||||
typedef struct {
|
||||
int numskins;
|
||||
} daliasskingroup_t;
|
||||
|
||||
typedef struct {
|
||||
float interval;
|
||||
} daliasinterval_t;
|
||||
|
||||
typedef struct {
|
||||
float interval;
|
||||
} daliasskininterval_t;
|
||||
|
||||
typedef struct {
|
||||
aliasframetype_t type;
|
||||
} daliasframetype_t;
|
||||
|
||||
typedef struct {
|
||||
aliasskintype_t type;
|
||||
} daliasskintype_t;
|
||||
|
||||
/* little-endian "IDPO" */
|
||||
#define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I')
|
||||
|
||||
#endif /* MODELGEN_H */
|
347
NQ/net.h
Normal file
347
NQ/net.h
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NET_H
|
||||
#define NET_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* net.h -- quake's interface to the networking layer */
|
||||
|
||||
struct qsockaddr {
|
||||
short sa_family;
|
||||
unsigned char sa_data[14];
|
||||
};
|
||||
|
||||
|
||||
#define NET_NAMELEN 64
|
||||
|
||||
#define NET_MAXMESSAGE 8192
|
||||
#define NET_HEADERSIZE (2 * sizeof(unsigned int))
|
||||
#define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE)
|
||||
|
||||
// NetHeader flags
|
||||
#define NETFLAG_LENGTH_MASK 0x0000ffff
|
||||
#define NETFLAG_DATA 0x00010000
|
||||
#define NETFLAG_ACK 0x00020000
|
||||
#define NETFLAG_NAK 0x00040000
|
||||
#define NETFLAG_EOM 0x00080000
|
||||
#define NETFLAG_UNRELIABLE 0x00100000
|
||||
#define NETFLAG_CTL 0x80000000
|
||||
|
||||
#define NET_PROTOCOL_VERSION 3
|
||||
|
||||
/*
|
||||
* This is the network info/connection protocol. It is used to find Quake
|
||||
* servers, get info about them, and connect to them. Once connected, the
|
||||
* Quake game protocol (documented elsewhere) is used.
|
||||
*
|
||||
* General notes:
|
||||
* game_name is currently always "QUAKE", but is there so this same protocol
|
||||
* can be used for future games as well; can you say Quake2?
|
||||
*
|
||||
* CCREQ_CONNECT
|
||||
* string game_name "QUAKE"
|
||||
* byte net_protocol_version NET_PROTOCOL_VERSION
|
||||
*
|
||||
* CCREQ_SERVER_INFO
|
||||
* string game_name "QUAKE"
|
||||
* byte net_protocol_version NET_PROTOCOL_VERSION
|
||||
*
|
||||
* CCREQ_PLAYER_INFO
|
||||
* byte player_number
|
||||
*
|
||||
* CCREQ_RULE_INFO
|
||||
* string rule
|
||||
*
|
||||
*
|
||||
*
|
||||
* CCREP_ACCEPT
|
||||
* long port
|
||||
*
|
||||
* CCREP_REJECT
|
||||
* string reason
|
||||
*
|
||||
* CCREP_SERVER_INFO
|
||||
* string server_address
|
||||
* string host_name
|
||||
* string level_name
|
||||
* byte current_players
|
||||
* byte max_players
|
||||
* byte protocol_version NET_PROTOCOL_VERSION
|
||||
*
|
||||
* CCREP_PLAYER_INFO
|
||||
* byte player_number
|
||||
* string name
|
||||
* long colors
|
||||
* long frags
|
||||
* long connect_time
|
||||
* string address
|
||||
*
|
||||
* CCREP_RULE_INFO
|
||||
* string rule
|
||||
* string value
|
||||
*
|
||||
* note:
|
||||
* There are two address forms used above. The short form is just a port
|
||||
* number. The address that goes along with the port is defined * as
|
||||
* "whatever address you receive this reponse from". This lets us * use
|
||||
* the host OS to solve the problem of multiple host addresses * (possibly
|
||||
* with no routing between them); the host will use the right * address
|
||||
* when we reply to the inbound connection request. The long * from is a
|
||||
* full address and port in a string. It is used for * returning the
|
||||
* address of a server that is not running locally.
|
||||
*/
|
||||
|
||||
#define CCREQ_CONNECT 0x01
|
||||
#define CCREQ_SERVER_INFO 0x02
|
||||
#define CCREQ_PLAYER_INFO 0x03
|
||||
#define CCREQ_RULE_INFO 0x04
|
||||
|
||||
#define CCREP_ACCEPT 0x81
|
||||
#define CCREP_REJECT 0x82
|
||||
#define CCREP_SERVER_INFO 0x83
|
||||
#define CCREP_PLAYER_INFO 0x84
|
||||
#define CCREP_RULE_INFO 0x85
|
||||
|
||||
struct net_landriver_s;
|
||||
struct net_driver_s;
|
||||
|
||||
typedef struct qsocket_s {
|
||||
struct qsocket_s *next;
|
||||
double connecttime;
|
||||
double lastMessageTime;
|
||||
double lastSendTime;
|
||||
|
||||
qboolean disconnected;
|
||||
qboolean canSend;
|
||||
qboolean sendNext;
|
||||
|
||||
struct net_driver_s *driver;
|
||||
struct net_landriver_s *landriver;
|
||||
int socket;
|
||||
void *driverdata;
|
||||
|
||||
unsigned int ackSequence;
|
||||
unsigned int sendSequence;
|
||||
unsigned int unreliableSendSequence;
|
||||
int sendMessageLength;
|
||||
byte sendMessage[NET_MAXMESSAGE];
|
||||
|
||||
unsigned int receiveSequence;
|
||||
unsigned int unreliableReceiveSequence;
|
||||
int receiveMessageLength;
|
||||
byte receiveMessage[NET_MAXMESSAGE];
|
||||
|
||||
struct qsockaddr addr;
|
||||
char address[NET_NAMELEN];
|
||||
|
||||
} qsocket_t;
|
||||
|
||||
extern qsocket_t *net_activeSockets;
|
||||
extern qsocket_t *net_freeSockets;
|
||||
|
||||
typedef struct net_landriver_s {
|
||||
char *name;
|
||||
qboolean initialized;
|
||||
int controlSock;
|
||||
int (*Init)(void);
|
||||
void (*Shutdown)(void);
|
||||
void (*Listen)(qboolean state);
|
||||
int (*OpenSocket)(int port);
|
||||
int (*CloseSocket)(int socket);
|
||||
int (*Connect)(int socket, struct qsockaddr *addr);
|
||||
int (*CheckNewConnections)(void);
|
||||
int (*Read)(int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int (*Write)(int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int (*Broadcast)(int socket, byte *buf, int len);
|
||||
char *(*AddrToString)(struct qsockaddr *addr);
|
||||
int (*StringToAddr)(char *string, struct qsockaddr *addr);
|
||||
int (*GetSocketAddr)(int socket, struct qsockaddr *addr);
|
||||
int (*GetNameFromAddr)(struct qsockaddr *addr, char *name);
|
||||
int (*GetAddrFromName)(char *name, struct qsockaddr *addr);
|
||||
int (*AddrCompare)(struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||
int (*GetSocketPort)(struct qsockaddr *addr);
|
||||
int (*SetSocketPort)(struct qsockaddr *addr, int port);
|
||||
} net_landriver_t;
|
||||
|
||||
#define MAX_NET_DRIVERS 8
|
||||
extern int net_numlandrivers;
|
||||
extern net_landriver_t net_landrivers[MAX_NET_DRIVERS];
|
||||
|
||||
typedef struct net_driver_s {
|
||||
char *name;
|
||||
qboolean initialized;
|
||||
int (*Init)(void);
|
||||
void (*Listen)(qboolean state);
|
||||
void (*SearchForHosts)(qboolean xmit);
|
||||
qsocket_t *(*Connect)(char *host);
|
||||
qsocket_t *(*CheckNewConnections)(void);
|
||||
int (*QGetMessage)(qsocket_t *sock);
|
||||
int (*QSendMessage)(qsocket_t *sock, sizebuf_t *data);
|
||||
int (*SendUnreliableMessage)(qsocket_t *sock, sizebuf_t *data);
|
||||
qboolean (*CanSendMessage)(qsocket_t *sock);
|
||||
qboolean (*CanSendUnreliableMessage)(qsocket_t *sock);
|
||||
void (*Close)(qsocket_t *sock);
|
||||
void (*Shutdown)(void);
|
||||
int controlSock;
|
||||
} net_driver_t;
|
||||
|
||||
extern int net_numdrivers;
|
||||
extern net_driver_t net_drivers[MAX_NET_DRIVERS];
|
||||
|
||||
extern int DEFAULTnet_hostport;
|
||||
extern int net_hostport;
|
||||
|
||||
extern net_driver_t *net_driver;
|
||||
extern cvar_t hostname;
|
||||
extern char playername[];
|
||||
extern int playercolor;
|
||||
|
||||
extern int messagesSent;
|
||||
extern int messagesReceived;
|
||||
extern int unreliableMessagesSent;
|
||||
extern int unreliableMessagesReceived;
|
||||
|
||||
qsocket_t *NET_NewQSocket(void);
|
||||
void NET_FreeQSocket(qsocket_t *);
|
||||
double SetNetTime(void);
|
||||
|
||||
|
||||
#define HOSTCACHESIZE 8
|
||||
|
||||
typedef struct {
|
||||
char name[16];
|
||||
char map[16];
|
||||
char cname[32];
|
||||
int users;
|
||||
int maxusers;
|
||||
net_driver_t *driver;
|
||||
net_landriver_t *ldriver;
|
||||
struct qsockaddr addr;
|
||||
} hostcache_t;
|
||||
|
||||
extern int hostCacheCount;
|
||||
extern hostcache_t hostcache[HOSTCACHESIZE];
|
||||
|
||||
#ifdef IDGODS
|
||||
qboolean IsID(struct qsockaddr *addr);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
*
|
||||
* public network functions
|
||||
*
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
extern double net_time;
|
||||
extern sizebuf_t net_message;
|
||||
extern int net_activeconnections;
|
||||
|
||||
void NET_Init(void);
|
||||
void NET_Shutdown(void);
|
||||
|
||||
/*
|
||||
* returns a new connection number if there is one pending, else -1
|
||||
*/
|
||||
struct qsocket_s *NET_CheckNewConnections(void);
|
||||
|
||||
/*
|
||||
* called by client to connect to a host. Returns -1 if not able to
|
||||
*/
|
||||
struct qsocket_s *NET_Connect(char *host);
|
||||
|
||||
/*
|
||||
* Returns true or false if the given qsocket can currently accept a message
|
||||
* to be transmitted.
|
||||
*/
|
||||
qboolean NET_CanSendMessage(qsocket_t *sock);
|
||||
|
||||
/*
|
||||
* returns data in net_message sizebuf
|
||||
* returns 0 if no data is waiting
|
||||
* returns 1 if a message was received
|
||||
* returns 2 if an unreliable message was received
|
||||
* returns -1 if the connection died
|
||||
*/
|
||||
int NET_GetMessage(struct qsocket_s *sock);
|
||||
|
||||
/*
|
||||
* returns 0 if the message connot be delivered reliably, but the connection
|
||||
* is still considered valid
|
||||
* returns 1 if the message was sent properly
|
||||
* returns -1 if the connection died
|
||||
*/
|
||||
int NET_SendMessage(struct qsocket_s *sock, sizebuf_t *data);
|
||||
int NET_SendUnreliableMessage(struct qsocket_s *sock, sizebuf_t *data);
|
||||
|
||||
/*
|
||||
* This is a reliable *blocking* send to all attached clients.
|
||||
*/
|
||||
int NET_SendToAll(sizebuf_t *data, int blocktime);
|
||||
|
||||
/*
|
||||
* if a dead connection is returned by a get or send function, this function
|
||||
* should be called when it is convenient
|
||||
*
|
||||
* Server calls when a client is kicked off for a game related misbehavior
|
||||
* like an illegal protocal conversation. Client calls when disconnecting
|
||||
* from a server. A netcon_t number will not be reused until this function is
|
||||
* called for it
|
||||
*/
|
||||
void NET_Close(struct qsocket_s *sock);
|
||||
|
||||
void NET_Poll(void);
|
||||
|
||||
typedef struct _PollProcedure {
|
||||
struct _PollProcedure *next;
|
||||
double nextTime;
|
||||
void (*procedure) ();
|
||||
void *arg;
|
||||
} PollProcedure;
|
||||
|
||||
void SchedulePollProcedure(PollProcedure *pp, double timeOffset);
|
||||
|
||||
extern qboolean serialAvailable;
|
||||
extern qboolean ipxAvailable;
|
||||
extern qboolean tcpipAvailable;
|
||||
extern char my_ipx_address[NET_NAMELEN];
|
||||
extern char my_tcpip_address[NET_NAMELEN];
|
||||
|
||||
extern void (*GetComPortConfig)(int portNumber, int *port, int *irq,
|
||||
int *baud, qboolean *useModem);
|
||||
extern void (*SetComPortConfig)(int portNumber, int port, int irq, int baud,
|
||||
qboolean useModem);
|
||||
extern void (*GetModemConfig)(int portNumber, char *dialType, char *clear,
|
||||
char *init, char *hangup);
|
||||
extern void (*SetModemConfig)(int portNumber, char *dialType, char *clear,
|
||||
char *init, char *hangup);
|
||||
|
||||
extern qboolean slistInProgress;
|
||||
extern qboolean slistSilent;
|
||||
extern qboolean slistLocal;
|
||||
|
||||
void NET_Slist_f(void);
|
||||
|
||||
extern qboolean recording;
|
||||
|
||||
#endif /* NET_H */
|
90
NQ/net_bsd.c
Normal file
90
NQ/net_bsd.c
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
#include "net_dgrm.h"
|
||||
#include "net_loop.h"
|
||||
#include "net_udp.h"
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
net_driver_t net_drivers[MAX_NET_DRIVERS] = {
|
||||
{
|
||||
.name = "Loopback",
|
||||
.initialized = false,
|
||||
.Init = Loop_Init,
|
||||
.Listen = Loop_Listen,
|
||||
.SearchForHosts = Loop_SearchForHosts,
|
||||
.Connect = Loop_Connect,
|
||||
.CheckNewConnections = Loop_CheckNewConnections,
|
||||
.QGetMessage = Loop_GetMessage,
|
||||
.QSendMessage = Loop_SendMessage,
|
||||
.SendUnreliableMessage = Loop_SendUnreliableMessage,
|
||||
.CanSendMessage = Loop_CanSendMessage,
|
||||
.CanSendUnreliableMessage = Loop_CanSendUnreliableMessage,
|
||||
.Close = Loop_Close,
|
||||
.Shutdown = Loop_Shutdown
|
||||
}, {
|
||||
.name = "Datagram",
|
||||
.initialized = false,
|
||||
.Init = Datagram_Init,
|
||||
.Listen = Datagram_Listen,
|
||||
.SearchForHosts = Datagram_SearchForHosts,
|
||||
.Connect = Datagram_Connect,
|
||||
.CheckNewConnections = Datagram_CheckNewConnections,
|
||||
.QGetMessage = Datagram_GetMessage,
|
||||
.QSendMessage = Datagram_SendMessage,
|
||||
.SendUnreliableMessage = Datagram_SendUnreliableMessage,
|
||||
.CanSendMessage = Datagram_CanSendMessage,
|
||||
.CanSendUnreliableMessage = Datagram_CanSendUnreliableMessage,
|
||||
.Close = Datagram_Close,
|
||||
.Shutdown = Datagram_Shutdown
|
||||
}
|
||||
};
|
||||
|
||||
int net_numdrivers = 2;
|
||||
|
||||
net_landriver_t net_landrivers[MAX_NET_DRIVERS] = {
|
||||
{
|
||||
.name = "UDP",
|
||||
.initialized = false,
|
||||
.controlSock = 0,
|
||||
.Init = UDP_Init,
|
||||
.Shutdown = UDP_Shutdown,
|
||||
.Listen = UDP_Listen,
|
||||
.OpenSocket = UDP_OpenSocket,
|
||||
.CloseSocket = UDP_CloseSocket,
|
||||
.Connect = UDP_Connect,
|
||||
.CheckNewConnections = UDP_CheckNewConnections,
|
||||
.Read = UDP_Read,
|
||||
.Write = UDP_Write,
|
||||
.Broadcast = UDP_Broadcast,
|
||||
.AddrToString = UDP_AddrToString,
|
||||
.StringToAddr = UDP_StringToAddr,
|
||||
.GetSocketAddr = UDP_GetSocketAddr,
|
||||
.GetNameFromAddr = UDP_GetNameFromAddr,
|
||||
.GetAddrFromName = UDP_GetAddrFromName,
|
||||
.AddrCompare = UDP_AddrCompare,
|
||||
.GetSocketPort = UDP_GetSocketPort,
|
||||
.SetSocketPort = UDP_SetSocketPort
|
||||
}
|
||||
};
|
||||
|
||||
int net_numlandrivers = 1;
|
1416
NQ/net_dgrm.c
Normal file
1416
NQ/net_dgrm.c
Normal file
File diff suppressed because it is too large
Load Diff
42
NQ/net_dgrm.h
Normal file
42
NQ/net_dgrm.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NET_DGRM_H
|
||||
#define NET_DGRM_H
|
||||
|
||||
#include "net.h"
|
||||
|
||||
// net_dgrm.h
|
||||
|
||||
|
||||
int Datagram_Init(void);
|
||||
void Datagram_Listen(qboolean state);
|
||||
void Datagram_SearchForHosts(qboolean xmit);
|
||||
qsocket_t *Datagram_Connect(char *host);
|
||||
qsocket_t *Datagram_CheckNewConnections(void);
|
||||
int Datagram_GetMessage(qsocket_t *sock);
|
||||
int Datagram_SendMessage(qsocket_t *sock, sizebuf_t *data);
|
||||
int Datagram_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data);
|
||||
qboolean Datagram_CanSendMessage(qsocket_t *sock);
|
||||
qboolean Datagram_CanSendUnreliableMessage(qsocket_t *sock);
|
||||
void Datagram_Close(qsocket_t *sock);
|
||||
void Datagram_Shutdown(void);
|
||||
|
||||
#endif /* NET_DGRM_H */
|
260
NQ/net_loop.c
Normal file
260
NQ/net_loop.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_loop.c
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "net_loop.h"
|
||||
#include "client.h"
|
||||
#include "server.h"
|
||||
#include "console.h"
|
||||
#include "sys.h"
|
||||
|
||||
qboolean localconnectpending = false;
|
||||
qsocket_t *loop_client = NULL;
|
||||
qsocket_t *loop_server = NULL;
|
||||
|
||||
int
|
||||
Loop_Init(void)
|
||||
{
|
||||
if (cls.state == ca_dedicated)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Loop_Shutdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Loop_Listen(qboolean state)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Loop_SearchForHosts(qboolean xmit)
|
||||
{
|
||||
if (!sv.active)
|
||||
return;
|
||||
|
||||
hostCacheCount = 1;
|
||||
if (strcmp(hostname.string, "UNNAMED") == 0)
|
||||
strcpy(hostcache[0].name, "local");
|
||||
else
|
||||
strcpy(hostcache[0].name, hostname.string);
|
||||
strcpy(hostcache[0].map, sv.name);
|
||||
hostcache[0].users = net_activeconnections;
|
||||
hostcache[0].maxusers = svs.maxclients;
|
||||
hostcache[0].driver = net_driver;
|
||||
strcpy(hostcache[0].cname, "local");
|
||||
}
|
||||
|
||||
|
||||
qsocket_t *
|
||||
Loop_Connect(char *host)
|
||||
{
|
||||
if (strcmp(host, "local") != 0)
|
||||
return NULL;
|
||||
|
||||
localconnectpending = true;
|
||||
|
||||
if (!loop_client) {
|
||||
if ((loop_client = NET_NewQSocket()) == NULL) {
|
||||
Con_Printf("Loop_Connect: no qsocket available\n");
|
||||
return NULL;
|
||||
}
|
||||
strcpy(loop_client->address, "localhost");
|
||||
}
|
||||
loop_client->receiveMessageLength = 0;
|
||||
loop_client->sendMessageLength = 0;
|
||||
loop_client->canSend = true;
|
||||
|
||||
if (!loop_server) {
|
||||
if ((loop_server = NET_NewQSocket()) == NULL) {
|
||||
Con_Printf("Loop_Connect: no qsocket available\n");
|
||||
return NULL;
|
||||
}
|
||||
strcpy(loop_server->address, "LOCAL");
|
||||
}
|
||||
loop_server->receiveMessageLength = 0;
|
||||
loop_server->sendMessageLength = 0;
|
||||
loop_server->canSend = true;
|
||||
|
||||
loop_client->driverdata = (void *)loop_server;
|
||||
loop_server->driverdata = (void *)loop_client;
|
||||
|
||||
return loop_client;
|
||||
}
|
||||
|
||||
|
||||
qsocket_t *
|
||||
Loop_CheckNewConnections(void)
|
||||
{
|
||||
if (!localconnectpending)
|
||||
return NULL;
|
||||
|
||||
localconnectpending = false;
|
||||
loop_server->sendMessageLength = 0;
|
||||
loop_server->receiveMessageLength = 0;
|
||||
loop_server->canSend = true;
|
||||
loop_client->sendMessageLength = 0;
|
||||
loop_client->receiveMessageLength = 0;
|
||||
loop_client->canSend = true;
|
||||
return loop_server;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
IntAlign(int value)
|
||||
{
|
||||
return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Loop_GetMessage(qsocket_t *sock)
|
||||
{
|
||||
int ret;
|
||||
int length;
|
||||
|
||||
if (sock->receiveMessageLength == 0)
|
||||
return 0;
|
||||
|
||||
ret = sock->receiveMessage[0];
|
||||
length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);
|
||||
// alignment byte skipped here
|
||||
SZ_Clear(&net_message);
|
||||
SZ_Write(&net_message, &sock->receiveMessage[4], length);
|
||||
|
||||
length = IntAlign(length + 4);
|
||||
sock->receiveMessageLength -= length;
|
||||
|
||||
if (sock->receiveMessageLength)
|
||||
memcpy(sock->receiveMessage, &sock->receiveMessage[length],
|
||||
sock->receiveMessageLength);
|
||||
|
||||
if (sock->driverdata && ret == 1)
|
||||
((qsocket_t *)sock->driverdata)->canSend = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Loop_SendMessage(qsocket_t *sock, sizebuf_t *data)
|
||||
{
|
||||
byte *buffer;
|
||||
int *bufferLength;
|
||||
|
||||
if (!sock->driverdata)
|
||||
return -1;
|
||||
|
||||
bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;
|
||||
|
||||
if ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE)
|
||||
Sys_Error("%s: overflow", __func__);
|
||||
|
||||
buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;
|
||||
|
||||
// message type
|
||||
*buffer++ = 1;
|
||||
|
||||
// length
|
||||
*buffer++ = data->cursize & 0xff;
|
||||
*buffer++ = data->cursize >> 8;
|
||||
|
||||
// align
|
||||
buffer++;
|
||||
|
||||
// message
|
||||
memcpy(buffer, data->data, data->cursize);
|
||||
*bufferLength = IntAlign(*bufferLength + data->cursize + 4);
|
||||
|
||||
sock->canSend = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Loop_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data)
|
||||
{
|
||||
byte *buffer;
|
||||
int *bufferLength;
|
||||
|
||||
if (!sock->driverdata)
|
||||
return -1;
|
||||
|
||||
bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;
|
||||
|
||||
if ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) >
|
||||
NET_MAXMESSAGE)
|
||||
return 0;
|
||||
|
||||
buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;
|
||||
|
||||
// message type
|
||||
*buffer++ = 2;
|
||||
|
||||
// length
|
||||
*buffer++ = data->cursize & 0xff;
|
||||
*buffer++ = data->cursize >> 8;
|
||||
|
||||
// align
|
||||
buffer++;
|
||||
|
||||
// message
|
||||
memcpy(buffer, data->data, data->cursize);
|
||||
*bufferLength = IntAlign(*bufferLength + data->cursize + 4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
qboolean
|
||||
Loop_CanSendMessage(qsocket_t *sock)
|
||||
{
|
||||
if (!sock->driverdata)
|
||||
return false;
|
||||
return sock->canSend;
|
||||
}
|
||||
|
||||
|
||||
qboolean
|
||||
Loop_CanSendUnreliableMessage(qsocket_t *sock)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Loop_Close(qsocket_t *sock)
|
||||
{
|
||||
if (sock->driverdata)
|
||||
((qsocket_t *)sock->driverdata)->driverdata = NULL;
|
||||
sock->receiveMessageLength = 0;
|
||||
sock->sendMessageLength = 0;
|
||||
sock->canSend = true;
|
||||
if (sock == loop_client)
|
||||
loop_client = NULL;
|
||||
else
|
||||
loop_server = NULL;
|
||||
}
|
41
NQ/net_loop.h
Normal file
41
NQ/net_loop.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NET_LOOP_H
|
||||
#define NET_LOOP_H
|
||||
|
||||
#include "net.h"
|
||||
|
||||
// net_loop.h
|
||||
|
||||
int Loop_Init(void);
|
||||
void Loop_Listen(qboolean state);
|
||||
void Loop_SearchForHosts(qboolean xmit);
|
||||
qsocket_t *Loop_Connect(char *host);
|
||||
qsocket_t *Loop_CheckNewConnections(void);
|
||||
int Loop_GetMessage(qsocket_t *sock);
|
||||
int Loop_SendMessage(qsocket_t *sock, sizebuf_t *data);
|
||||
int Loop_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data);
|
||||
qboolean Loop_CanSendMessage(qsocket_t *sock);
|
||||
qboolean Loop_CanSendUnreliableMessage(qsocket_t *sock);
|
||||
void Loop_Close(qsocket_t *sock);
|
||||
void Loop_Shutdown(void);
|
||||
|
||||
#endif /* NET_LOOP_H */
|
985
NQ/net_main.c
Normal file
985
NQ/net_main.c
Normal file
@ -0,0 +1,985 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "cmd.h"
|
||||
#include "console.h"
|
||||
#include "net_vcr.h"
|
||||
#include "quakedef.h"
|
||||
#include "server.h"
|
||||
#include "sys.h"
|
||||
#include "zone.h"
|
||||
|
||||
qsocket_t *net_activeSockets = NULL;
|
||||
qsocket_t *net_freeSockets = NULL;
|
||||
static int net_numsockets = 0;
|
||||
|
||||
qboolean serialAvailable = false;
|
||||
qboolean ipxAvailable = false;
|
||||
qboolean tcpipAvailable = false;
|
||||
|
||||
int net_hostport;
|
||||
int DEFAULTnet_hostport = 26000;
|
||||
|
||||
char my_ipx_address[NET_NAMELEN];
|
||||
char my_tcpip_address[NET_NAMELEN];
|
||||
|
||||
void (*GetComPortConfig)(int portNumber, int *port, int *irq,
|
||||
int *baud, qboolean *useModem);
|
||||
void (*SetComPortConfig)(int portNumber, int port, int irq, int baud,
|
||||
qboolean useModem);
|
||||
void (*GetModemConfig)(int portNumber, char *dialType, char *clear,
|
||||
char *init, char *hangup);
|
||||
void (*SetModemConfig)(int portNumber, char *dialType, char *clear,
|
||||
char *init, char *hangup);
|
||||
|
||||
static qboolean listening = false;
|
||||
|
||||
qboolean slistInProgress = false;
|
||||
qboolean slistSilent = false;
|
||||
qboolean slistLocal = true;
|
||||
#define IS_LOOP_DRIVER(p) ((p) == &net_drivers[0])
|
||||
|
||||
static double slistStartTime;
|
||||
static int slistLastShown;
|
||||
|
||||
static void Slist_Send(void);
|
||||
static void Slist_Poll(void);
|
||||
static PollProcedure slistSendProcedure = { NULL, 0.0, Slist_Send };
|
||||
static PollProcedure slistPollProcedure = { NULL, 0.0, Slist_Poll };
|
||||
|
||||
sizebuf_t net_message;
|
||||
int net_activeconnections = 0;
|
||||
|
||||
int messagesSent = 0;
|
||||
int messagesReceived = 0;
|
||||
int unreliableMessagesSent = 0;
|
||||
int unreliableMessagesReceived = 0;
|
||||
|
||||
cvar_t net_messagetimeout = { "net_messagetimeout", "300" };
|
||||
cvar_t hostname = { "hostname", "UNNAMED" };
|
||||
|
||||
qboolean configRestored = false;
|
||||
cvar_t config_com_port = { "_config_com_port", "0x3f8", true };
|
||||
cvar_t config_com_irq = { "_config_com_irq", "4", true };
|
||||
cvar_t config_com_baud = { "_config_com_baud", "57600", true };
|
||||
cvar_t config_com_modem = { "_config_com_modem", "1", true };
|
||||
cvar_t config_modem_dialtype = { "_config_modem_dialtype", "T", true };
|
||||
cvar_t config_modem_clear = { "_config_modem_clear", "ATZ", true };
|
||||
cvar_t config_modem_init = { "_config_modem_init", "", true };
|
||||
cvar_t config_modem_hangup = { "_config_modem_hangup", "AT H", true };
|
||||
|
||||
#ifdef IDGODS
|
||||
cvar_t idgods = { "idgods", "0" };
|
||||
#endif
|
||||
|
||||
qboolean recording = false;
|
||||
|
||||
net_driver_t *net_driver;
|
||||
double net_time;
|
||||
|
||||
|
||||
double
|
||||
SetNetTime(void)
|
||||
{
|
||||
net_time = Sys_DoubleTime();
|
||||
return net_time;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ===================
|
||||
* NET_NewQSocket
|
||||
*
|
||||
* Called by drivers when a new communications endpoint is required
|
||||
* The sequence and buffer fields will be filled in properly
|
||||
* ===================
|
||||
*/
|
||||
qsocket_t *
|
||||
NET_NewQSocket(void)
|
||||
{
|
||||
qsocket_t *sock;
|
||||
|
||||
if (!net_freeSockets)
|
||||
return NULL;
|
||||
|
||||
if (net_activeconnections >= svs.maxclients)
|
||||
return NULL;
|
||||
|
||||
/* get one from free list */
|
||||
sock = net_freeSockets;
|
||||
net_freeSockets = sock->next;
|
||||
|
||||
/* add it to active list */
|
||||
sock->next = net_activeSockets;
|
||||
net_activeSockets = sock;
|
||||
|
||||
sock->disconnected = false;
|
||||
sock->connecttime = net_time;
|
||||
strcpy(sock->address, "UNSET ADDRESS");
|
||||
sock->driver = net_driver;
|
||||
sock->socket = 0;
|
||||
sock->driverdata = NULL;
|
||||
sock->canSend = true;
|
||||
sock->sendNext = false;
|
||||
sock->lastMessageTime = net_time;
|
||||
sock->ackSequence = 0;
|
||||
sock->sendSequence = 0;
|
||||
sock->unreliableSendSequence = 0;
|
||||
sock->sendMessageLength = 0;
|
||||
sock->receiveSequence = 0;
|
||||
sock->unreliableReceiveSequence = 0;
|
||||
sock->receiveMessageLength = 0;
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NET_FreeQSocket(qsocket_t *sock)
|
||||
{
|
||||
qsocket_t *s;
|
||||
|
||||
/* remove it from active list */
|
||||
if (sock == net_activeSockets)
|
||||
net_activeSockets = net_activeSockets->next;
|
||||
else {
|
||||
for (s = net_activeSockets; s; s = s->next)
|
||||
if (s->next == sock) {
|
||||
s->next = sock->next;
|
||||
break;
|
||||
}
|
||||
if (!s)
|
||||
Sys_Error("%s: not active", __func__);
|
||||
}
|
||||
|
||||
/* add it to free list */
|
||||
sock->next = net_freeSockets;
|
||||
net_freeSockets = sock;
|
||||
sock->disconnected = true;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
NET_Listen_f(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (Cmd_Argc() != 2) {
|
||||
Con_Printf("\"listen\" is \"%u\"\n", listening ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
listening = Q_atoi(Cmd_Argv(1)) ? true : false;
|
||||
|
||||
for (i = 0; i < net_numdrivers;i++) {
|
||||
net_driver = &net_drivers[i];
|
||||
if (net_driver->initialized == false)
|
||||
continue;
|
||||
net_driver->Listen(listening);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
MaxPlayers_f(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (Cmd_Argc() != 2) {
|
||||
Con_Printf("\"maxplayers\" is \"%u\"\n", svs.maxclients);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sv.active) {
|
||||
Con_Printf
|
||||
("maxplayers can not be changed while a server is running.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
n = Q_atoi(Cmd_Argv(1));
|
||||
if (n < 1)
|
||||
n = 1;
|
||||
if (n > svs.maxclientslimit) {
|
||||
n = svs.maxclientslimit;
|
||||
Con_Printf("\"maxplayers\" set to \"%u\"\n", n);
|
||||
}
|
||||
|
||||
if ((n == 1) && listening)
|
||||
Cbuf_AddText("listen 0\n");
|
||||
|
||||
if ((n > 1) && (!listening))
|
||||
Cbuf_AddText("listen 1\n");
|
||||
|
||||
svs.maxclients = n;
|
||||
if (n == 1) {
|
||||
Cvar_Set("deathmatch", "0");
|
||||
Cvar_Set("coop", "0");
|
||||
} else {
|
||||
if (coop.value)
|
||||
Cvar_Set("deathmatch", "0");
|
||||
else
|
||||
Cvar_Set("deathmatch", "1");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
NET_Port_f(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (Cmd_Argc() != 2) {
|
||||
Con_Printf("\"port\" is \"%u\"\n", net_hostport);
|
||||
return;
|
||||
}
|
||||
|
||||
n = Q_atoi(Cmd_Argv(1));
|
||||
if (n < 1 || n > 65534) {
|
||||
Con_Printf("Bad value, must be between 1 and 65534\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DEFAULTnet_hostport = n;
|
||||
net_hostport = n;
|
||||
|
||||
if (listening) {
|
||||
/* force a change to the new port */
|
||||
Cbuf_AddText("listen 0\n");
|
||||
Cbuf_AddText("listen 1\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
PrintSlistHeader(void)
|
||||
{
|
||||
Con_Printf("Server Map Users\n");
|
||||
Con_Printf("--------------- --------------- -----\n");
|
||||
slistLastShown = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
PrintSlist(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = slistLastShown; n < hostCacheCount; n++) {
|
||||
if (hostcache[n].maxusers)
|
||||
Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name,
|
||||
hostcache[n].map, hostcache[n].users,
|
||||
hostcache[n].maxusers);
|
||||
else
|
||||
Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name,
|
||||
hostcache[n].map);
|
||||
}
|
||||
slistLastShown = n;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
PrintSlistTrailer(void)
|
||||
{
|
||||
if (hostCacheCount)
|
||||
Con_Printf("== end list ==\n\n");
|
||||
else
|
||||
Con_Printf("No Quake servers found.\n\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NET_Slist_f(void)
|
||||
{
|
||||
if (slistInProgress)
|
||||
return;
|
||||
|
||||
if (!slistSilent) {
|
||||
Con_Printf("Looking for Quake servers...\n");
|
||||
PrintSlistHeader();
|
||||
}
|
||||
|
||||
slistInProgress = true;
|
||||
slistStartTime = Sys_DoubleTime();
|
||||
|
||||
SchedulePollProcedure(&slistSendProcedure, 0.0);
|
||||
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
||||
|
||||
hostCacheCount = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Slist_Send(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < net_numdrivers; i++) {
|
||||
net_driver = &net_drivers[i];
|
||||
|
||||
/* Only list the loop driver if slistLocal is true */
|
||||
if (!slistLocal && IS_LOOP_DRIVER(net_driver))
|
||||
continue;
|
||||
if (net_driver->initialized == false)
|
||||
continue;
|
||||
net_driver->SearchForHosts(true);
|
||||
}
|
||||
|
||||
if ((Sys_DoubleTime() - slistStartTime) < 0.5)
|
||||
SchedulePollProcedure(&slistSendProcedure, 0.75);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
Slist_Poll(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < net_numdrivers; i++) {
|
||||
net_driver = &net_drivers[i];
|
||||
|
||||
/* Only list the loop driver if slistLocal is true */
|
||||
if (!slistLocal && IS_LOOP_DRIVER(net_driver))
|
||||
continue;
|
||||
if (net_driver->initialized == false)
|
||||
continue;
|
||||
net_driver->SearchForHosts(false);
|
||||
}
|
||||
|
||||
if (!slistSilent)
|
||||
PrintSlist();
|
||||
|
||||
if ((Sys_DoubleTime() - slistStartTime) < 1.5) {
|
||||
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!slistSilent)
|
||||
PrintSlistTrailer();
|
||||
slistInProgress = false;
|
||||
slistSilent = false;
|
||||
slistLocal = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ===================
|
||||
* NET_Connect
|
||||
* ===================
|
||||
*/
|
||||
int hostCacheCount = 0;
|
||||
hostcache_t hostcache[HOSTCACHESIZE];
|
||||
|
||||
qsocket_t *
|
||||
NET_Connect(char *host)
|
||||
{
|
||||
qsocket_t *ret;
|
||||
int i, n;
|
||||
int numdrivers = net_numdrivers;
|
||||
|
||||
SetNetTime();
|
||||
|
||||
if (host && *host == 0)
|
||||
host = NULL;
|
||||
|
||||
if (host) {
|
||||
if (strcasecmp(host, "local") == 0) {
|
||||
numdrivers = 1;
|
||||
goto JustDoIt;
|
||||
}
|
||||
|
||||
if (hostCacheCount) {
|
||||
for (n = 0; n < hostCacheCount; n++)
|
||||
if (strcasecmp(host, hostcache[n].name) == 0) {
|
||||
host = hostcache[n].cname;
|
||||
break;
|
||||
}
|
||||
if (n < hostCacheCount)
|
||||
goto JustDoIt;
|
||||
}
|
||||
}
|
||||
|
||||
slistSilent = host ? true : false;
|
||||
NET_Slist_f();
|
||||
|
||||
while (slistInProgress)
|
||||
NET_Poll();
|
||||
|
||||
if (host == NULL) {
|
||||
if (hostCacheCount != 1)
|
||||
return NULL;
|
||||
host = hostcache[0].cname;
|
||||
Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
|
||||
}
|
||||
|
||||
if (hostCacheCount)
|
||||
for (n = 0; n < hostCacheCount; n++)
|
||||
if (strcasecmp(host, hostcache[n].name) == 0) {
|
||||
host = hostcache[n].cname;
|
||||
break;
|
||||
}
|
||||
|
||||
JustDoIt:
|
||||
for (i = 0; i < numdrivers; i++) {
|
||||
net_driver = &net_drivers[i];
|
||||
if (net_driver->initialized == false)
|
||||
continue;
|
||||
ret = net_driver->Connect(host);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (host) {
|
||||
Con_Printf("\n");
|
||||
PrintSlistHeader();
|
||||
PrintSlist();
|
||||
PrintSlistTrailer();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ===================
|
||||
* NET_CheckNewConnections
|
||||
* ===================
|
||||
*/
|
||||
static struct {
|
||||
double time;
|
||||
int op;
|
||||
long session;
|
||||
} vcrConnect;
|
||||
|
||||
qsocket_t *
|
||||
NET_CheckNewConnections(void)
|
||||
{
|
||||
int i;
|
||||
qsocket_t *ret;
|
||||
|
||||
SetNetTime();
|
||||
|
||||
for (i = 0; i < net_numdrivers; i++) {
|
||||
net_driver = &net_drivers[i];
|
||||
if (net_driver->initialized == false)
|
||||
continue;
|
||||
if (!IS_LOOP_DRIVER(net_driver) && listening == false)
|
||||
continue;
|
||||
ret = net_driver->CheckNewConnections();
|
||||
if (ret) {
|
||||
if (recording) {
|
||||
vcrConnect.time = host_time;
|
||||
vcrConnect.op = VCR_OP_CONNECT;
|
||||
vcrConnect.session = (long)ret;
|
||||
Sys_FileWrite(vcrFile, &vcrConnect, sizeof(vcrConnect));
|
||||
Sys_FileWrite(vcrFile, ret->address, NET_NAMELEN);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (recording) {
|
||||
vcrConnect.time = host_time;
|
||||
vcrConnect.op = VCR_OP_CONNECT;
|
||||
vcrConnect.session = 0;
|
||||
Sys_FileWrite(vcrFile, &vcrConnect, sizeof(vcrConnect));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===================
|
||||
* NET_Close
|
||||
* ===================
|
||||
*/
|
||||
void
|
||||
NET_Close(qsocket_t *sock)
|
||||
{
|
||||
if (!sock)
|
||||
return;
|
||||
|
||||
if (sock->disconnected)
|
||||
return;
|
||||
|
||||
SetNetTime();
|
||||
|
||||
/* call the driver_Close function */
|
||||
sock->driver->Close(sock);
|
||||
|
||||
NET_FreeQSocket(sock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* =================
|
||||
* NET_GetMessage
|
||||
*
|
||||
* If there is a complete message, return it in net_message
|
||||
*
|
||||
* returns 0 if no data is waiting
|
||||
* returns 1 if a message was received
|
||||
* returns -1 if connection is invalid
|
||||
* =================
|
||||
*/
|
||||
static struct {
|
||||
double time;
|
||||
int op;
|
||||
long session;
|
||||
int ret;
|
||||
int len;
|
||||
} vcrGetMessage;
|
||||
|
||||
int
|
||||
NET_GetMessage(qsocket_t *sock)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sock)
|
||||
return -1;
|
||||
|
||||
if (sock->disconnected) {
|
||||
Con_Printf("%s: disconnected socket\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetNetTime();
|
||||
|
||||
ret = sock->driver->QGetMessage(sock);
|
||||
|
||||
/* see if this connection has timed out (not for loop) */
|
||||
if (ret == 0 && (!IS_LOOP_DRIVER(sock->driver))) {
|
||||
if (net_time - sock->lastMessageTime > net_messagetimeout.value) {
|
||||
NET_Close(sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ret > 0) {
|
||||
if (!IS_LOOP_DRIVER(sock->driver)) {
|
||||
sock->lastMessageTime = net_time;
|
||||
if (ret == 1)
|
||||
messagesReceived++;
|
||||
else if (ret == 2)
|
||||
unreliableMessagesReceived++;
|
||||
}
|
||||
|
||||
if (recording) {
|
||||
vcrGetMessage.time = host_time;
|
||||
vcrGetMessage.op = VCR_OP_GETMESSAGE;
|
||||
vcrGetMessage.session = (long)sock;
|
||||
vcrGetMessage.ret = ret;
|
||||
vcrGetMessage.len = net_message.cursize;
|
||||
Sys_FileWrite(vcrFile, &vcrGetMessage, 24);
|
||||
Sys_FileWrite(vcrFile, net_message.data, net_message.cursize);
|
||||
}
|
||||
} else {
|
||||
if (recording) {
|
||||
vcrGetMessage.time = host_time;
|
||||
vcrGetMessage.op = VCR_OP_GETMESSAGE;
|
||||
vcrGetMessage.session = (long)sock;
|
||||
vcrGetMessage.ret = ret;
|
||||
Sys_FileWrite(vcrFile, &vcrGetMessage, 20);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ==================
|
||||
* NET_SendMessage
|
||||
*
|
||||
* Try to send a complete length+message unit over the reliable stream.
|
||||
* returns 0 : if the message cannot be delivered reliably, but the connection
|
||||
* is still considered valid
|
||||
* returns 1 : if the message was sent properly
|
||||
* returns -1 : if the connection died
|
||||
* ==================
|
||||
*/
|
||||
static struct {
|
||||
double time;
|
||||
int op;
|
||||
long session;
|
||||
int r;
|
||||
} vcrSendMessage;
|
||||
|
||||
int
|
||||
NET_SendMessage(qsocket_t *sock, sizebuf_t *data)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!sock)
|
||||
return -1;
|
||||
|
||||
if (sock->disconnected) {
|
||||
Con_Printf("%s: disconnected socket\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
SetNetTime();
|
||||
r = sock->driver->QSendMessage(sock, data);
|
||||
if (r == 1 && !IS_LOOP_DRIVER(sock->driver))
|
||||
messagesSent++;
|
||||
|
||||
if (recording) {
|
||||
vcrSendMessage.time = host_time;
|
||||
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
|
||||
vcrSendMessage.session = (long)sock;
|
||||
vcrSendMessage.r = r;
|
||||
Sys_FileWrite(vcrFile, &vcrSendMessage, 20);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
NET_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!sock)
|
||||
return -1;
|
||||
|
||||
if (sock->disconnected) {
|
||||
Con_Printf("NET_SendMessage: disconnected socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetNetTime();
|
||||
r = sock->driver->SendUnreliableMessage(sock, data);
|
||||
if (r == 1 && !IS_LOOP_DRIVER(sock->driver))
|
||||
unreliableMessagesSent++;
|
||||
|
||||
if (recording) {
|
||||
vcrSendMessage.time = host_time;
|
||||
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
|
||||
vcrSendMessage.session = (long)sock;
|
||||
vcrSendMessage.r = r;
|
||||
Sys_FileWrite(vcrFile, &vcrSendMessage, 20);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ==================
|
||||
* NET_CanSendMessage
|
||||
*
|
||||
* Returns true or false if the given qsocket can currently accept a
|
||||
* message to be transmitted.
|
||||
* ==================
|
||||
*/
|
||||
qboolean
|
||||
NET_CanSendMessage(qsocket_t *sock)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!sock)
|
||||
return false;
|
||||
|
||||
if (sock->disconnected)
|
||||
return false;
|
||||
|
||||
SetNetTime();
|
||||
|
||||
r = sock->driver->CanSendMessage(sock);
|
||||
|
||||
if (recording) {
|
||||
vcrSendMessage.time = host_time;
|
||||
vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
|
||||
vcrSendMessage.session = (long)sock;
|
||||
vcrSendMessage.r = r;
|
||||
Sys_FileWrite(vcrFile, &vcrSendMessage, 20);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
NET_SendToAll(sizebuf_t *data, int blocktime)
|
||||
{
|
||||
double start;
|
||||
int i;
|
||||
int count = 0;
|
||||
qboolean state1[MAX_SCOREBOARD];
|
||||
qboolean state2[MAX_SCOREBOARD];
|
||||
|
||||
for (i = 0, host_client = svs.clients; i < svs.maxclients;
|
||||
i++, host_client++) {
|
||||
if (!host_client->netconnection)
|
||||
continue;
|
||||
if (host_client->active) {
|
||||
if (host_client->netconnection->driver == net_drivers) {
|
||||
NET_SendMessage(host_client->netconnection, data);
|
||||
state1[i] = true;
|
||||
state2[i] = true;
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
state1[i] = false;
|
||||
state2[i] = false;
|
||||
} else {
|
||||
state1[i] = true;
|
||||
state2[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
start = Sys_DoubleTime();
|
||||
while (count) {
|
||||
count = 0;
|
||||
for (i = 0, host_client = svs.clients; i < svs.maxclients;
|
||||
i++, host_client++) {
|
||||
if (!state1[i]) {
|
||||
if (NET_CanSendMessage(host_client->netconnection)) {
|
||||
state1[i] = true;
|
||||
NET_SendMessage(host_client->netconnection, data);
|
||||
} else {
|
||||
NET_GetMessage(host_client->netconnection);
|
||||
}
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!state2[i]) {
|
||||
if (NET_CanSendMessage(host_client->netconnection)) {
|
||||
state2[i] = true;
|
||||
} else {
|
||||
NET_GetMessage(host_client->netconnection);
|
||||
}
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((Sys_DoubleTime() - start) > blocktime)
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ====================
|
||||
* NET_Init
|
||||
* ====================
|
||||
*/
|
||||
void
|
||||
NET_Init(void)
|
||||
{
|
||||
int i;
|
||||
int controlSocket;
|
||||
qsocket_t *s;
|
||||
|
||||
if (COM_CheckParm("-playback")) {
|
||||
net_numdrivers = 1;
|
||||
net_drivers[0].Init = VCR_Init;
|
||||
}
|
||||
|
||||
if (COM_CheckParm("-record"))
|
||||
recording = true;
|
||||
|
||||
i = COM_CheckParm("-port");
|
||||
if (!i)
|
||||
i = COM_CheckParm("-udpport");
|
||||
if (!i)
|
||||
i = COM_CheckParm("-ipxport");
|
||||
|
||||
if (i) {
|
||||
if (i < com_argc - 1)
|
||||
DEFAULTnet_hostport = Q_atoi(com_argv[i + 1]);
|
||||
else
|
||||
Sys_Error("%s: you must specify a number after -port", __func__);
|
||||
}
|
||||
net_hostport = DEFAULTnet_hostport;
|
||||
|
||||
if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
|
||||
listening = true;
|
||||
net_numsockets = svs.maxclientslimit;
|
||||
if (cls.state != ca_dedicated)
|
||||
net_numsockets++;
|
||||
|
||||
SetNetTime();
|
||||
|
||||
for (i = 0; i < net_numsockets; i++) {
|
||||
s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
|
||||
s->next = net_freeSockets;
|
||||
net_freeSockets = s;
|
||||
s->disconnected = true;
|
||||
}
|
||||
|
||||
/* allocate space for network message buffer */
|
||||
SZ_Alloc(&net_message, NET_MAXMESSAGE);
|
||||
|
||||
Cvar_RegisterVariable(&net_messagetimeout);
|
||||
Cvar_RegisterVariable(&hostname);
|
||||
Cvar_RegisterVariable(&config_com_port);
|
||||
Cvar_RegisterVariable(&config_com_irq);
|
||||
Cvar_RegisterVariable(&config_com_baud);
|
||||
Cvar_RegisterVariable(&config_com_modem);
|
||||
Cvar_RegisterVariable(&config_modem_dialtype);
|
||||
Cvar_RegisterVariable(&config_modem_clear);
|
||||
Cvar_RegisterVariable(&config_modem_init);
|
||||
Cvar_RegisterVariable(&config_modem_hangup);
|
||||
#ifdef IDGODS
|
||||
Cvar_RegisterVariable(&idgods);
|
||||
#endif
|
||||
|
||||
Cmd_AddCommand("slist", NET_Slist_f);
|
||||
Cmd_AddCommand("listen", NET_Listen_f);
|
||||
Cmd_AddCommand("maxplayers", MaxPlayers_f);
|
||||
Cmd_AddCommand("port", NET_Port_f);
|
||||
|
||||
/* initialize all the drivers */
|
||||
for (i = 0; i < net_numdrivers; i++) {
|
||||
net_driver = &net_drivers[i];
|
||||
controlSocket = net_driver->Init();
|
||||
if (controlSocket == -1)
|
||||
continue;
|
||||
net_driver->initialized = true;
|
||||
net_driver->controlSock = controlSocket;
|
||||
if (listening)
|
||||
net_driver->Listen(true);
|
||||
}
|
||||
|
||||
if (*my_ipx_address)
|
||||
Con_DPrintf("IPX address %s\n", my_ipx_address);
|
||||
if (*my_tcpip_address)
|
||||
Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
|
||||
}
|
||||
|
||||
/*
|
||||
* ====================
|
||||
* NET_Shutdown
|
||||
* ====================
|
||||
*/
|
||||
void
|
||||
NET_Shutdown(void)
|
||||
{
|
||||
int i;
|
||||
qsocket_t *sock;
|
||||
|
||||
SetNetTime();
|
||||
|
||||
for (sock = net_activeSockets; sock; sock = sock->next)
|
||||
NET_Close(sock);
|
||||
|
||||
/*
|
||||
* shutdown the drivers
|
||||
*/
|
||||
for (i = 0; i < net_numdrivers; i++) {
|
||||
net_driver = &net_drivers[i];
|
||||
if (net_driver->initialized == true) {
|
||||
net_driver->Shutdown();
|
||||
net_driver->initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (vcrFile != -1) {
|
||||
Con_Printf("Closing vcrfile.\n");
|
||||
Sys_FileClose(vcrFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static PollProcedure *pollProcedureList = NULL;
|
||||
|
||||
void
|
||||
NET_Poll(void)
|
||||
{
|
||||
PollProcedure *pp;
|
||||
qboolean useModem;
|
||||
|
||||
if (!configRestored) {
|
||||
if (serialAvailable) {
|
||||
if (config_com_modem.value == 1.0)
|
||||
useModem = true;
|
||||
else
|
||||
useModem = false;
|
||||
SetComPortConfig(0, (int)config_com_port.value,
|
||||
(int)config_com_irq.value,
|
||||
(int)config_com_baud.value, useModem);
|
||||
SetModemConfig(0, config_modem_dialtype.string,
|
||||
config_modem_clear.string,
|
||||
config_modem_init.string,
|
||||
config_modem_hangup.string);
|
||||
}
|
||||
configRestored = true;
|
||||
}
|
||||
|
||||
SetNetTime();
|
||||
|
||||
/*
|
||||
* FIXME - A procedure could schedule itself to the head of the list, but
|
||||
* wouldn't be executed until next frame/tic; problem?
|
||||
*/
|
||||
for (pp = pollProcedureList; pp; pp = pp->next) {
|
||||
if (pp->nextTime > net_time)
|
||||
break;
|
||||
pollProcedureList = pp->next;
|
||||
pp->procedure(pp->arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SchedulePollProcedure(PollProcedure *proc, double timeOffset)
|
||||
{
|
||||
PollProcedure *pp, *prev;
|
||||
|
||||
proc->nextTime = Sys_DoubleTime() + timeOffset;
|
||||
for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next) {
|
||||
if (pp->nextTime >= proc->nextTime)
|
||||
break;
|
||||
prev = pp;
|
||||
}
|
||||
|
||||
if (prev == NULL) {
|
||||
proc->next = pollProcedureList;
|
||||
pollProcedureList = proc;
|
||||
return;
|
||||
}
|
||||
|
||||
proc->next = pp;
|
||||
prev->next = proc;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IDGODS
|
||||
#define IDNET 0xc0f62800
|
||||
|
||||
qboolean
|
||||
IsID(struct qsockaddr *addr)
|
||||
{
|
||||
if (idgods.value == 0.0)
|
||||
return false;
|
||||
|
||||
if (addr->sa_family != 2)
|
||||
return false;
|
||||
|
||||
if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
44
NQ/net_none.c
Normal file
44
NQ/net_none.c
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "quakedef.h"
|
||||
|
||||
#include "net_loop.h"
|
||||
|
||||
net_driver_t net_drivers[MAX_NET_DRIVERS] = {
|
||||
{
|
||||
"Loopback",
|
||||
false,
|
||||
Loop_Init,
|
||||
Loop_Listen,
|
||||
Loop_SearchForHosts,
|
||||
Loop_Connect,
|
||||
Loop_CheckNewConnections,
|
||||
Loop_GetMessage,
|
||||
Loop_SendMessage,
|
||||
Loop_SendUnreliableMessage,
|
||||
Loop_CanSendMessage,
|
||||
Loop_CanSendUnreliableMessage,
|
||||
Loop_Close,
|
||||
Loop_Shutdown}
|
||||
};
|
||||
int net_numdrivers = 1;
|
||||
|
||||
net_landriver_t net_landrivers[MAX_NET_DRIVERS];
|
||||
int net_numlandrivers = 0;
|
41
NQ/net_ser.h
Normal file
41
NQ/net_ser.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NET_SER_H
|
||||
#define NET_SER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "net.h"
|
||||
#include "qtypes.h"
|
||||
|
||||
int Serial_Init(void);
|
||||
void Serial_Listen(qboolean state);
|
||||
void Serial_SearchForHosts(qboolean xmit);
|
||||
qsocket_t *Serial_Connect(char *host);
|
||||
qsocket_t *Serial_CheckNewConnections(void);
|
||||
int Serial_GetMessage(qsocket_t *sock);
|
||||
int Serial_SendMessage(qsocket_t *sock, sizebuf_t *data);
|
||||
int Serial_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data);
|
||||
qboolean Serial_CanSendMessage(qsocket_t *sock);
|
||||
qboolean Serial_CanSendUnreliableMessage(qsocket_t *sock);
|
||||
void Serial_Close(qsocket_t *sock);
|
||||
void Serial_Shutdown(void);
|
||||
|
||||
#endif /* NET_SER_H */
|
409
NQ/net_udp.c
Normal file
409
NQ/net_udp.c
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "net.h"
|
||||
#include "net_udp.h"
|
||||
#include "quakedef.h"
|
||||
#include "sys.h"
|
||||
|
||||
/* socket for fielding new connections */
|
||||
static int net_acceptsocket = -1;
|
||||
static int net_controlsocket;
|
||||
static int net_broadcastsocket = 0;
|
||||
static struct qsockaddr broadcastaddr;
|
||||
static unsigned long myAddr;
|
||||
|
||||
|
||||
int
|
||||
UDP_Init(void)
|
||||
{
|
||||
struct hostent *local;
|
||||
char buff[MAXHOSTNAMELEN];
|
||||
struct qsockaddr addr;
|
||||
char *colon;
|
||||
|
||||
if (COM_CheckParm("-noudp"))
|
||||
return -1;
|
||||
|
||||
/* determine my name & address */
|
||||
gethostname(buff, MAXHOSTNAMELEN);
|
||||
local = gethostbyname(buff);
|
||||
myAddr = *(int *)local->h_addr_list[0];
|
||||
|
||||
/* if the quake hostname isn't set, set it to the machine name */
|
||||
if (strcmp(hostname.string, "UNNAMED") == 0) {
|
||||
buff[15] = 0; /* FIXME - 15? */
|
||||
Cvar_Set("hostname", buff);
|
||||
}
|
||||
|
||||
if ((net_controlsocket = UDP_OpenSocket(0)) == -1)
|
||||
Sys_Error("%s: Unable to open control socket", __func__);
|
||||
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr =
|
||||
INADDR_BROADCAST;
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport);
|
||||
|
||||
UDP_GetSocketAddr(net_controlsocket, &addr);
|
||||
strcpy(my_tcpip_address, UDP_AddrToString(&addr));
|
||||
colon = strrchr(my_tcpip_address, ':');
|
||||
if (colon)
|
||||
*colon = 0;
|
||||
|
||||
Con_Printf("UDP Initialized\n");
|
||||
tcpipAvailable = true;
|
||||
|
||||
return net_controlsocket;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UDP_Shutdown(void)
|
||||
{
|
||||
UDP_Listen(false);
|
||||
UDP_CloseSocket(net_controlsocket);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UDP_Listen(qboolean state)
|
||||
{
|
||||
/* enable listening */
|
||||
if (state) {
|
||||
if (net_acceptsocket != -1)
|
||||
return;
|
||||
if ((net_acceptsocket = UDP_OpenSocket(net_hostport)) == -1)
|
||||
Sys_Error("%s: Unable to open accept socket", __func__);
|
||||
return;
|
||||
}
|
||||
/* disable listening */
|
||||
if (net_acceptsocket == -1)
|
||||
return;
|
||||
UDP_CloseSocket(net_acceptsocket);
|
||||
net_acceptsocket = -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_OpenSocket(int port)
|
||||
{
|
||||
int newsocket;
|
||||
struct sockaddr_in address;
|
||||
qboolean _true = true;
|
||||
|
||||
if ((newsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
return -1;
|
||||
|
||||
if (ioctl(newsocket, FIONBIO, (char *)&_true) == -1)
|
||||
goto ErrorReturn;
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(port);
|
||||
if (bind(newsocket, (void *)&address, sizeof(address)) == -1)
|
||||
goto ErrorReturn;
|
||||
|
||||
return newsocket;
|
||||
|
||||
ErrorReturn:
|
||||
close(newsocket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_CloseSocket(int socket)
|
||||
{
|
||||
if (socket == net_broadcastsocket)
|
||||
net_broadcastsocket = 0;
|
||||
return close(socket);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============
|
||||
* PartialIPAddress
|
||||
*
|
||||
* this lets you type only as much of the net address as required,
|
||||
* using the local network components to fill in the rest
|
||||
* ============
|
||||
*/
|
||||
static int
|
||||
PartialIPAddress(char *in, struct qsockaddr *hostaddr)
|
||||
{
|
||||
char buff[256];
|
||||
char *b;
|
||||
int addr;
|
||||
int num;
|
||||
int mask;
|
||||
int run;
|
||||
int port;
|
||||
|
||||
buff[0] = '.';
|
||||
b = buff;
|
||||
strcpy(buff + 1, in);
|
||||
if (buff[1] == '.')
|
||||
b++;
|
||||
|
||||
addr = 0;
|
||||
mask = -1;
|
||||
while (*b == '.') {
|
||||
b++;
|
||||
num = 0;
|
||||
run = 0;
|
||||
while (!(*b < '0' || *b > '9')) {
|
||||
num = num * 10 + *b++ - '0';
|
||||
if (++run > 3)
|
||||
return -1;
|
||||
}
|
||||
if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
|
||||
return -1;
|
||||
if (num < 0 || num > 255)
|
||||
return -1;
|
||||
mask <<= 8;
|
||||
addr = (addr << 8) + num;
|
||||
}
|
||||
|
||||
if (*b++ == ':')
|
||||
port = Q_atoi(b);
|
||||
else
|
||||
port = net_hostport;
|
||||
|
||||
hostaddr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
|
||||
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr =
|
||||
(myAddr & htonl(mask)) | htonl(addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_Connect(int socket, struct qsockaddr *addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_CheckNewConnections(void)
|
||||
{
|
||||
unsigned long available;
|
||||
|
||||
if (net_acceptsocket == -1)
|
||||
return -1;
|
||||
|
||||
if (ioctl(net_acceptsocket, FIONREAD, &available) == -1)
|
||||
Sys_Error("%s: ioctlsocket (FIONREAD) failed", __func__);
|
||||
if (available)
|
||||
return net_acceptsocket;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_Read(int socket, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
int addrlen = sizeof(struct qsockaddr);
|
||||
int ret;
|
||||
|
||||
ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
|
||||
if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED))
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_MakeSocketBroadcastCapable(int socket)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
/* make this socket broadcast capable */
|
||||
if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i))
|
||||
< 0)
|
||||
return -1;
|
||||
net_broadcastsocket = socket;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_Broadcast(int socket, byte *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (socket != net_broadcastsocket) {
|
||||
if (net_broadcastsocket != 0)
|
||||
Sys_Error("Attempted to use multiple broadcasts sockets");
|
||||
ret = UDP_MakeSocketBroadcastCapable(socket);
|
||||
if (ret == -1) {
|
||||
Con_Printf("Unable to make socket broadcast capable\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return UDP_Write(socket, buf, len, &broadcastaddr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_Write(int socket, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret =
|
||||
sendto(socket, buf, len, 0, (struct sockaddr *)addr,
|
||||
sizeof(struct qsockaddr));
|
||||
if (ret == -1 && errno == EWOULDBLOCK)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
UDP_AddrToString(struct qsockaddr *addr)
|
||||
{
|
||||
static char buffer[22];
|
||||
int haddr;
|
||||
|
||||
haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_StringToAddr(char *string, struct qsockaddr *addr)
|
||||
{
|
||||
int ha1, ha2, ha3, ha4, hp;
|
||||
int ipaddr;
|
||||
|
||||
sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
|
||||
ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
|
||||
|
||||
addr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(hp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_GetSocketAddr(int socket, struct qsockaddr *addr)
|
||||
{
|
||||
int addrlen = sizeof(struct qsockaddr);
|
||||
unsigned int a;
|
||||
|
||||
memset(addr, 0, sizeof(struct qsockaddr));
|
||||
getsockname(socket, (struct sockaddr *)addr, &addrlen);
|
||||
a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
||||
if (a == 0 || a == inet_addr("127.0.0.1"))
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_GetNameFromAddr(struct qsockaddr *addr, char *name)
|
||||
{
|
||||
struct hostent *hostentry;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
strcpy(name, UDP_AddrToString(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_GetAddrFromName(char *name, struct qsockaddr *addr)
|
||||
{
|
||||
struct hostent *hostentry;
|
||||
|
||||
if (name[0] >= '0' && name[0] <= '9')
|
||||
return PartialIPAddress(name, addr);
|
||||
|
||||
hostentry = gethostbyname(name);
|
||||
if (!hostentry)
|
||||
return -1;
|
||||
|
||||
addr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr =
|
||||
*(int *)hostentry->h_addr_list[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_AddrCompare(struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||
{
|
||||
if (addr1->sa_family != addr2->sa_family)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_GetSocketPort(struct qsockaddr *addr)
|
||||
{
|
||||
return ntohs(((struct sockaddr_in *)addr)->sin_port);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
UDP_SetSocketPort(struct qsockaddr *addr, int port)
|
||||
{
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(port);
|
||||
return 0;
|
||||
}
|
47
NQ/net_udp.h
Normal file
47
NQ/net_udp.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NET_UDP_H
|
||||
#define NET_UDP_H
|
||||
|
||||
#include "net.h"
|
||||
|
||||
// net_udp.h
|
||||
|
||||
int UDP_Init(void);
|
||||
void UDP_Shutdown(void);
|
||||
void UDP_Listen(qboolean state);
|
||||
int UDP_OpenSocket(int port);
|
||||
int UDP_CloseSocket(int socket);
|
||||
int UDP_Connect(int socket, struct qsockaddr *addr);
|
||||
int UDP_CheckNewConnections(void);
|
||||
int UDP_Read(int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int UDP_Write(int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int UDP_Broadcast(int socket, byte *buf, int len);
|
||||
char *UDP_AddrToString(struct qsockaddr *addr);
|
||||
int UDP_StringToAddr(char *string, struct qsockaddr *addr);
|
||||
int UDP_GetSocketAddr(int socket, struct qsockaddr *addr);
|
||||
int UDP_GetNameFromAddr(struct qsockaddr *addr, char *name);
|
||||
int UDP_GetAddrFromName(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);
|
||||
|
||||
#endif /* NET_UDP_H */
|
181
NQ/net_vcr.c
Normal file
181
NQ/net_vcr.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_vcr.c
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "net_vcr.h"
|
||||
#include "sys.h"
|
||||
#include "server.h"
|
||||
|
||||
int vcrFile = -1;
|
||||
|
||||
/*
|
||||
* This is the playback portion of the VCR. It reads the file produced by the
|
||||
* recorder and plays it back to the host. The recording contains everything
|
||||
* necessary (events, timestamps, and data) to duplicate the game from the
|
||||
* viewpoint of everything above the network layer.
|
||||
*/
|
||||
|
||||
static struct {
|
||||
double time;
|
||||
int op;
|
||||
long session;
|
||||
} next;
|
||||
|
||||
int
|
||||
VCR_Init(void)
|
||||
{
|
||||
net_drivers[0].Init = VCR_Init;
|
||||
net_drivers[0].SearchForHosts = VCR_SearchForHosts;
|
||||
net_drivers[0].Connect = VCR_Connect;
|
||||
net_drivers[0].CheckNewConnections = VCR_CheckNewConnections;
|
||||
net_drivers[0].QGetMessage = VCR_GetMessage;
|
||||
net_drivers[0].QSendMessage = VCR_SendMessage;
|
||||
net_drivers[0].CanSendMessage = VCR_CanSendMessage;
|
||||
net_drivers[0].Close = VCR_Close;
|
||||
net_drivers[0].Shutdown = VCR_Shutdown;
|
||||
|
||||
Sys_FileRead(vcrFile, &next, sizeof(next));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
VCR_ReadNext(void)
|
||||
{
|
||||
if (Sys_FileRead(vcrFile, &next, sizeof(next)) == 0) {
|
||||
next.op = 255;
|
||||
Sys_Error("=== END OF PLAYBACK===");
|
||||
}
|
||||
if (next.op < 1 || next.op > VCR_MAX_MESSAGE)
|
||||
Sys_Error("%s: bad op", __func__);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VCR_Listen(qboolean state)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VCR_Shutdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
VCR_GetMessage(qsocket_t *sock)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (host_time != next.time || next.op != VCR_OP_GETMESSAGE
|
||||
|| next.session != *(long *)(&sock->driverdata))
|
||||
Sys_Error("VCR missmatch");
|
||||
|
||||
Sys_FileRead(vcrFile, &ret, sizeof(int));
|
||||
if (ret != 1) {
|
||||
VCR_ReadNext();
|
||||
return ret;
|
||||
}
|
||||
|
||||
Sys_FileRead(vcrFile, &net_message.cursize, sizeof(int));
|
||||
Sys_FileRead(vcrFile, net_message.data, net_message.cursize);
|
||||
|
||||
VCR_ReadNext();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
VCR_SendMessage(qsocket_t *sock, sizebuf_t *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (host_time != next.time || next.op != VCR_OP_SENDMESSAGE
|
||||
|| next.session != *(long *)(&sock->driverdata))
|
||||
Sys_Error("VCR missmatch");
|
||||
|
||||
Sys_FileRead(vcrFile, &ret, sizeof(int));
|
||||
|
||||
VCR_ReadNext();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
qboolean
|
||||
VCR_CanSendMessage(qsocket_t *sock)
|
||||
{
|
||||
qboolean ret;
|
||||
|
||||
if (host_time != next.time || next.op != VCR_OP_CANSENDMESSAGE
|
||||
|| next.session != *(long *)(&sock->driverdata))
|
||||
Sys_Error("VCR missmatch");
|
||||
|
||||
Sys_FileRead(vcrFile, &ret, sizeof(int));
|
||||
|
||||
VCR_ReadNext();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VCR_Close(qsocket_t *sock)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VCR_SearchForHosts(qboolean xmit)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
qsocket_t *
|
||||
VCR_Connect(char *host)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
qsocket_t *
|
||||
VCR_CheckNewConnections(void)
|
||||
{
|
||||
qsocket_t *sock;
|
||||
|
||||
if (host_time != next.time || next.op != VCR_OP_CONNECT)
|
||||
Sys_Error("VCR missmatch");
|
||||
|
||||
if (!next.session) {
|
||||
VCR_ReadNext();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sock = NET_NewQSocket();
|
||||
*(long *)(&sock->driverdata) = next.session;
|
||||
|
||||
Sys_FileRead(vcrFile, sock->address, NET_NAMELEN);
|
||||
VCR_ReadNext();
|
||||
|
||||
return sock;
|
||||
}
|
47
NQ/net_vcr.h
Normal file
47
NQ/net_vcr.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NET_VCR_H
|
||||
#define NET_VCR_H
|
||||
|
||||
#include "net.h"
|
||||
|
||||
// net_vcr.h
|
||||
|
||||
#define VCR_OP_CONNECT 1
|
||||
#define VCR_OP_GETMESSAGE 2
|
||||
#define VCR_OP_SENDMESSAGE 3
|
||||
#define VCR_OP_CANSENDMESSAGE 4
|
||||
#define VCR_MAX_MESSAGE 4
|
||||
|
||||
extern int vcrFile;
|
||||
|
||||
int VCR_Init(void);
|
||||
void VCR_Listen(qboolean state);
|
||||
void VCR_SearchForHosts(qboolean xmit);
|
||||
qsocket_t *VCR_Connect(char *host);
|
||||
qsocket_t *VCR_CheckNewConnections(void);
|
||||
int VCR_GetMessage(qsocket_t *sock);
|
||||
int VCR_SendMessage(qsocket_t *sock, sizebuf_t *data);
|
||||
qboolean VCR_CanSendMessage(qsocket_t *sock);
|
||||
void VCR_Close(qsocket_t *sock);
|
||||
void VCR_Shutdown(void);
|
||||
|
||||
#endif /* NET_VCR_H */
|
115
NQ/net_win.c
Normal file
115
NQ/net_win.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
#include "net_dgrm.h"
|
||||
#include "net_loop.h"
|
||||
#include "net_ser.h"
|
||||
#include "net_wins.h"
|
||||
#include "net_wipx.h"
|
||||
|
||||
#include "quakedef.h"
|
||||
|
||||
net_driver_t net_drivers[MAX_NET_DRIVERS] = {
|
||||
{
|
||||
.name = "Loopback",
|
||||
.initialized = false,
|
||||
.Init = Loop_Init,
|
||||
.Listen = Loop_Listen,
|
||||
.SearchForHosts = Loop_SearchForHosts,
|
||||
.Connect = Loop_Connect,
|
||||
.CheckNewConnections = Loop_CheckNewConnections,
|
||||
.QGetMessage = Loop_GetMessage,
|
||||
.QSendMessage = Loop_SendMessage,
|
||||
.SendUnreliableMessage = Loop_SendUnreliableMessage,
|
||||
.CanSendMessage = Loop_CanSendMessage,
|
||||
.CanSendUnreliableMessage = Loop_CanSendUnreliableMessage,
|
||||
.Close = Loop_Close,
|
||||
.Shutdown = Loop_Shutdown
|
||||
}, {
|
||||
.name = "Datagram",
|
||||
.initialized = false,
|
||||
.Init = Datagram_Init,
|
||||
.Listen = Datagram_Listen,
|
||||
.SearchForHosts = Datagram_SearchForHosts,
|
||||
.Connect = Datagram_Connect,
|
||||
.CheckNewConnections = Datagram_CheckNewConnections,
|
||||
.QGetMessage = Datagram_GetMessage,
|
||||
.QSendMessage = Datagram_SendMessage,
|
||||
.SendUnreliableMessage = Datagram_SendUnreliableMessage,
|
||||
.CanSendMessage = Datagram_CanSendMessage,
|
||||
.CanSendUnreliableMessage = Datagram_CanSendUnreliableMessage,
|
||||
.Close = Datagram_Close,
|
||||
.Shutdown = Datagram_Shutdown
|
||||
}
|
||||
};
|
||||
|
||||
int net_numdrivers = 2;
|
||||
|
||||
|
||||
net_landriver_t net_landrivers[MAX_NET_DRIVERS] = {
|
||||
{
|
||||
.name = "Winsock TCPIP",
|
||||
.initialized = false,
|
||||
.controlSock = 0,
|
||||
.Init = WINS_Init,
|
||||
.Shutdown = WINS_Shutdown,
|
||||
.Listen = WINS_Listen,
|
||||
.OpenSocket = WINS_OpenSocket,
|
||||
.CloseSocket = WINS_CloseSocket,
|
||||
.Connect = WINS_Connect,
|
||||
.CheckNewConnections = WINS_CheckNewConnections,
|
||||
.Read = WINS_Read,
|
||||
.Write = WINS_Write,
|
||||
.Broadcast = WINS_Broadcast,
|
||||
.AddrToString = WINS_AddrToString,
|
||||
.StringToAddr = WINS_StringToAddr,
|
||||
.GetSocketAddr = WINS_GetSocketAddr,
|
||||
.GetNameFromAddr = WINS_GetNameFromAddr,
|
||||
.GetAddrFromName = WINS_GetAddrFromName,
|
||||
.AddrCompare = WINS_AddrCompare,
|
||||
.GetSocketPort = WINS_GetSocketPort,
|
||||
.SetSocketPort = WINS_SetSocketPort
|
||||
}, {
|
||||
.name = "Winsock IPX",
|
||||
.initialized = false,
|
||||
.controlSock = 0,
|
||||
.Init = WIPX_Init,
|
||||
.Shutdown = WIPX_Shutdown,
|
||||
.Listen = WIPX_Listen,
|
||||
.OpenSocket = WIPX_OpenSocket,
|
||||
.CloseSocket = WIPX_CloseSocket,
|
||||
.Connect = WIPX_Connect,
|
||||
.CheckNewConnections = WIPX_CheckNewConnections,
|
||||
.Read = WIPX_Read,
|
||||
.Write = WIPX_Write,
|
||||
.Broadcast = WIPX_Broadcast,
|
||||
.AddrToString = WIPX_AddrToString,
|
||||
.StringToAddr = WIPX_StringToAddr,
|
||||
.GetSocketAddr = WIPX_GetSocketAddr,
|
||||
.GetNameFromAddr = WIPX_GetNameFromAddr,
|
||||
.GetAddrFromName = WIPX_GetAddrFromName,
|
||||
.AddrCompare = WIPX_AddrCompare,
|
||||
.GetSocketPort = WIPX_GetSocketPort,
|
||||
.SetSocketPort = WIPX_SetSocketPort
|
||||
}
|
||||
};
|
||||
|
||||
int net_numlandrivers = 2;
|
576
NQ/net_wins.c
Normal file
576
NQ/net_wins.c
Normal file
@ -0,0 +1,576 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "console.h"
|
||||
#include "net.h"
|
||||
#include "net_wins.h"
|
||||
#include "quakedef.h"
|
||||
#include "sys.h"
|
||||
#include "winquake.h"
|
||||
|
||||
/* socket for fielding new connections */
|
||||
static int net_acceptsocket = -1;
|
||||
static int net_controlsocket;
|
||||
static int net_broadcastsocket = 0;
|
||||
static struct qsockaddr broadcastaddr;
|
||||
|
||||
static unsigned long myAddr;
|
||||
|
||||
qboolean winsock_lib_initialized;
|
||||
|
||||
int (PASCAL FAR *pWSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
|
||||
int (PASCAL FAR *pWSACleanup) (void);
|
||||
int (PASCAL FAR *pWSAGetLastError) (void);
|
||||
|
||||
SOCKET (PASCAL FAR *psocket) (int af, int type, int protocol);
|
||||
int (PASCAL FAR *pioctlsocket) (SOCKET s, long cmd, u_long FAR *argp);
|
||||
int (PASCAL FAR *psetsockopt) (SOCKET s, int level, int optname,
|
||||
const char FAR *optval, int optlen);
|
||||
int (PASCAL FAR *precvfrom) (SOCKET s, char FAR *buf, int len,
|
||||
int flags, struct sockaddr FAR *from,
|
||||
int FAR *fromlen);
|
||||
int (PASCAL FAR *psendto) (SOCKET s, const char FAR *buf, int len,
|
||||
int flags, const struct sockaddr FAR *to,
|
||||
int tolen);
|
||||
int (PASCAL FAR *pclosesocket) (SOCKET s);
|
||||
int (PASCAL FAR *pgethostname) (char FAR *name, int namelen);
|
||||
struct hostent FAR *(PASCAL FAR *pgethostbyname)(const char FAR *name);
|
||||
struct hostent FAR *(PASCAL FAR *pgethostbyaddr)(const char FAR *addr,
|
||||
int len, int type);
|
||||
int (PASCAL FAR *pgetsockname) (SOCKET s, struct sockaddr FAR *name,
|
||||
int FAR *namelen);
|
||||
|
||||
int winsock_initialized = 0;
|
||||
WSADATA winsockdata;
|
||||
|
||||
static double blocktime;
|
||||
|
||||
|
||||
BOOL PASCAL FAR
|
||||
BlockingHook(void)
|
||||
{
|
||||
MSG msg;
|
||||
BOOL ret;
|
||||
|
||||
if ((Sys_DoubleTime() - blocktime) > 2.0) {
|
||||
WSACancelBlockingCall();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* get the next message, if any */
|
||||
ret = (BOOL)PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
|
||||
|
||||
/* if we got one, process it */
|
||||
if (ret) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
/* TRUE if we got a message */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WINS_GetLocalAddress()
|
||||
{
|
||||
struct hostent *local = NULL;
|
||||
char buff[MAXHOSTNAMELEN];
|
||||
unsigned long addr;
|
||||
|
||||
if (myAddr != INADDR_ANY)
|
||||
return;
|
||||
|
||||
if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
|
||||
return;
|
||||
|
||||
blocktime = Sys_DoubleTime();
|
||||
WSASetBlockingHook(BlockingHook);
|
||||
local = pgethostbyname(buff);
|
||||
WSAUnhookBlockingHook();
|
||||
if (local == NULL)
|
||||
return;
|
||||
|
||||
myAddr = *(int *)local->h_addr_list[0];
|
||||
|
||||
addr = ntohl(myAddr);
|
||||
sprintf(my_tcpip_address, "%ld.%ld.%ld.%ld", (addr >> 24) & 0xff,
|
||||
(addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_Init(void)
|
||||
{
|
||||
int i;
|
||||
char buff[MAXHOSTNAMELEN];
|
||||
char *p;
|
||||
int r;
|
||||
WORD wVersionRequested;
|
||||
HINSTANCE hInst;
|
||||
|
||||
/*
|
||||
* initialize the Winsock function vectors (we do this instead of
|
||||
* statically linking so we can run on Win 3.1, where there isn't
|
||||
* necessarily Winsock)
|
||||
*/
|
||||
hInst = LoadLibrary("wsock32.dll");
|
||||
|
||||
if (hInst == NULL) {
|
||||
Con_SafePrintf("Failed to load winsock.dll\n");
|
||||
winsock_lib_initialized = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
winsock_lib_initialized = true;
|
||||
|
||||
pWSAStartup = (void *)GetProcAddress(hInst, "WSAStartup");
|
||||
pWSACleanup = (void *)GetProcAddress(hInst, "WSACleanup");
|
||||
pWSAGetLastError = (void *)GetProcAddress(hInst, "WSAGetLastError");
|
||||
psocket = (void *)GetProcAddress(hInst, "socket");
|
||||
pioctlsocket = (void *)GetProcAddress(hInst, "ioctlsocket");
|
||||
psetsockopt = (void *)GetProcAddress(hInst, "setsockopt");
|
||||
precvfrom = (void *)GetProcAddress(hInst, "recvfrom");
|
||||
psendto = (void *)GetProcAddress(hInst, "sendto");
|
||||
pclosesocket = (void *)GetProcAddress(hInst, "closesocket");
|
||||
pgethostname = (void *)GetProcAddress(hInst, "gethostname");
|
||||
pgethostbyname = (void *)GetProcAddress(hInst, "gethostbyname");
|
||||
pgethostbyaddr = (void *)GetProcAddress(hInst, "gethostbyaddr");
|
||||
pgetsockname = (void *)GetProcAddress(hInst, "getsockname");
|
||||
|
||||
if (!pWSAStartup || !pWSACleanup || !pWSAGetLastError ||
|
||||
!psocket || !pioctlsocket || !psetsockopt ||
|
||||
!precvfrom || !psendto || !pclosesocket ||
|
||||
!pgethostname || !pgethostbyname || !pgethostbyaddr ||
|
||||
!pgetsockname) {
|
||||
Con_SafePrintf("Couldn't GetProcAddress from winsock.dll\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (COM_CheckParm("-noudp"))
|
||||
return -1;
|
||||
|
||||
if (winsock_initialized == 0) {
|
||||
wVersionRequested = MAKEWORD(1, 1);
|
||||
|
||||
r = pWSAStartup(MAKEWORD(1, 1), &winsockdata);
|
||||
|
||||
if (r) {
|
||||
Con_SafePrintf("Winsock initialization failed.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
winsock_initialized++;
|
||||
|
||||
/* determine my name */
|
||||
if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR) {
|
||||
Con_DPrintf("Winsock TCP/IP Initialization failed.\n");
|
||||
if (--winsock_initialized == 0)
|
||||
pWSACleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if the quake hostname isn't set, set it to the machine name */
|
||||
if (strcmp(hostname.string, "UNNAMED") == 0) {
|
||||
/* see if it's a text IP address (well, close enough) */
|
||||
for (p = buff; *p; p++)
|
||||
if ((*p < '0' || *p > '9') && *p != '.')
|
||||
break;
|
||||
|
||||
/* if it is a real name, strip off the domain; we only want the host */
|
||||
if (*p) {
|
||||
for (i = 0; i < 15; i++)
|
||||
if (buff[i] == '.')
|
||||
break;
|
||||
buff[i] = 0;
|
||||
}
|
||||
Cvar_Set("hostname", buff);
|
||||
}
|
||||
|
||||
i = COM_CheckParm("-ip");
|
||||
if (i) {
|
||||
if (i < com_argc - 1) {
|
||||
myAddr = inet_addr(com_argv[i + 1]);
|
||||
if (myAddr == INADDR_NONE)
|
||||
Sys_Error("%s is not a valid IP address", com_argv[i + 1]);
|
||||
strcpy(my_tcpip_address, com_argv[i + 1]);
|
||||
} else {
|
||||
Sys_Error("%s: you must specify an IP address after -ip",
|
||||
__func__);
|
||||
}
|
||||
} else {
|
||||
myAddr = INADDR_ANY;
|
||||
strcpy(my_tcpip_address, "INADDR_ANY");
|
||||
}
|
||||
|
||||
if ((net_controlsocket = WINS_OpenSocket(0)) == -1) {
|
||||
Con_Printf("WINS_Init: Unable to open control socket\n");
|
||||
if (--winsock_initialized == 0)
|
||||
pWSACleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr =
|
||||
INADDR_BROADCAST;
|
||||
((struct sockaddr_in *)&broadcastaddr)->sin_port =
|
||||
htons((unsigned short)net_hostport);
|
||||
|
||||
Con_Printf("Winsock TCP/IP Initialized\n");
|
||||
tcpipAvailable = true;
|
||||
|
||||
return net_controlsocket;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WINS_Shutdown(void)
|
||||
{
|
||||
WINS_Listen(false);
|
||||
WINS_CloseSocket(net_controlsocket);
|
||||
if (--winsock_initialized == 0)
|
||||
pWSACleanup();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WINS_Listen(qboolean state)
|
||||
{
|
||||
/* enable listening */
|
||||
if (state) {
|
||||
if (net_acceptsocket != -1)
|
||||
return;
|
||||
WINS_GetLocalAddress();
|
||||
if ((net_acceptsocket = WINS_OpenSocket(net_hostport)) == -1)
|
||||
Sys_Error("%s: Unable to open accept socket", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* disable listening */
|
||||
if (net_acceptsocket == -1)
|
||||
return;
|
||||
|
||||
WINS_CloseSocket(net_acceptsocket);
|
||||
net_acceptsocket = -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_OpenSocket(int port)
|
||||
{
|
||||
int newsocket;
|
||||
struct sockaddr_in address;
|
||||
u_long _true = 1;
|
||||
|
||||
if ((newsocket = psocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
return -1;
|
||||
|
||||
if (pioctlsocket(newsocket, FIONBIO, &_true) == -1)
|
||||
goto ErrorReturn;
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = myAddr;
|
||||
address.sin_port = htons((unsigned short)port);
|
||||
if (bind(newsocket, (void *)&address, sizeof(address)) == 0)
|
||||
return newsocket;
|
||||
|
||||
Sys_Error("Unable to bind to %s",
|
||||
WINS_AddrToString((struct qsockaddr *)&address));
|
||||
ErrorReturn:
|
||||
pclosesocket(newsocket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_CloseSocket(int socket)
|
||||
{
|
||||
if (socket == net_broadcastsocket)
|
||||
net_broadcastsocket = 0;
|
||||
return pclosesocket(socket);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ============
|
||||
* PartialIPAddress
|
||||
*
|
||||
* this lets you type only as much of the net address as required, using the
|
||||
* local network components to fill in the rest
|
||||
* ============
|
||||
*/
|
||||
static int
|
||||
PartialIPAddress(char *in, struct qsockaddr *hostaddr)
|
||||
{
|
||||
char buff[256];
|
||||
char *b;
|
||||
int addr;
|
||||
int num;
|
||||
int mask;
|
||||
int run;
|
||||
int port;
|
||||
|
||||
buff[0] = '.';
|
||||
b = buff;
|
||||
strcpy(buff + 1, in);
|
||||
if (buff[1] == '.')
|
||||
b++;
|
||||
|
||||
addr = 0;
|
||||
mask = -1;
|
||||
while (*b == '.') {
|
||||
b++;
|
||||
num = 0;
|
||||
run = 0;
|
||||
while (!(*b < '0' || *b > '9')) {
|
||||
num = num * 10 + *b++ - '0';
|
||||
if (++run > 3)
|
||||
return -1;
|
||||
}
|
||||
if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
|
||||
return -1;
|
||||
if (num < 0 || num > 255)
|
||||
return -1;
|
||||
mask <<= 8;
|
||||
addr = (addr << 8) + num;
|
||||
}
|
||||
|
||||
if (*b++ == ':')
|
||||
port = Q_atoi(b);
|
||||
else
|
||||
port = net_hostport;
|
||||
|
||||
hostaddr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
|
||||
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr =
|
||||
(myAddr & htonl(mask)) | htonl(addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_Connect(int socket, struct qsockaddr *addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_CheckNewConnections(void)
|
||||
{
|
||||
char buf[4096];
|
||||
|
||||
if (net_acceptsocket == -1)
|
||||
return -1;
|
||||
|
||||
if (precvfrom(net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL)
|
||||
> 0) {
|
||||
return net_acceptsocket;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_Read(int socket, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
int addrlen = sizeof(struct qsockaddr);
|
||||
int ret;
|
||||
|
||||
ret = precvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
|
||||
if (ret == -1) {
|
||||
int err = pWSAGetLastError();
|
||||
|
||||
if (err == WSAEWOULDBLOCK || err == WSAECONNREFUSED)
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_MakeSocketBroadcastCapable(int socket)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
/* make this socket broadcast capable */
|
||||
if (psetsockopt
|
||||
(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
|
||||
return -1;
|
||||
net_broadcastsocket = socket;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_Broadcast(int socket, byte *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (socket != net_broadcastsocket) {
|
||||
if (net_broadcastsocket != 0)
|
||||
Sys_Error("Attempted to use multiple broadcasts sockets");
|
||||
WINS_GetLocalAddress();
|
||||
ret = WINS_MakeSocketBroadcastCapable(socket);
|
||||
if (ret == -1) {
|
||||
Con_Printf("Unable to make socket broadcast capable\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return WINS_Write(socket, buf, len, &broadcastaddr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_Write(int socket, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret =
|
||||
psendto(socket, buf, len, 0, (struct sockaddr *)addr,
|
||||
sizeof(struct qsockaddr));
|
||||
if (ret == -1)
|
||||
if (pWSAGetLastError() == WSAEWOULDBLOCK)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
WINS_AddrToString(struct qsockaddr *addr)
|
||||
{
|
||||
static char buffer[22];
|
||||
int haddr;
|
||||
|
||||
haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_StringToAddr(char *string, struct qsockaddr *addr)
|
||||
{
|
||||
int ha1, ha2, ha3, ha4, hp;
|
||||
int ipaddr;
|
||||
|
||||
sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
|
||||
ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
|
||||
|
||||
addr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
|
||||
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_GetSocketAddr(int socket, struct qsockaddr *addr)
|
||||
{
|
||||
int addrlen = sizeof(struct qsockaddr);
|
||||
unsigned int a;
|
||||
|
||||
memset(addr, 0, sizeof(struct qsockaddr));
|
||||
pgetsockname(socket, (struct sockaddr *)addr, &addrlen);
|
||||
a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
||||
if (a == 0 || a == inet_addr("127.0.0.1"))
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_GetNameFromAddr(struct qsockaddr *addr, char *name)
|
||||
{
|
||||
struct hostent *hostentry;
|
||||
|
||||
hostentry =
|
||||
pgethostbyaddr((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;
|
||||
}
|
||||
|
||||
strcpy(name, WINS_AddrToString(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_GetAddrFromName(char *name, struct qsockaddr *addr)
|
||||
{
|
||||
struct hostent *hostentry;
|
||||
|
||||
if (name[0] >= '0' && name[0] <= '9')
|
||||
return PartialIPAddress(name, addr);
|
||||
|
||||
hostentry = pgethostbyname(name);
|
||||
if (!hostentry)
|
||||
return -1;
|
||||
|
||||
addr->sa_family = AF_INET;
|
||||
((struct sockaddr_in *)addr)->sin_port =
|
||||
htons((unsigned short)net_hostport);
|
||||
((struct sockaddr_in *)addr)->sin_addr.s_addr =
|
||||
*(int *)hostentry->h_addr_list[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_AddrCompare(struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||
{
|
||||
if (addr1->sa_family != addr2->sa_family)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_GetSocketPort(struct qsockaddr *addr)
|
||||
{
|
||||
return ntohs(((struct sockaddr_in *)addr)->sin_port);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WINS_SetSocketPort(struct qsockaddr *addr, int port)
|
||||
{
|
||||
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
|
||||
return 0;
|
||||
}
|
43
NQ/net_wins.h
Normal file
43
NQ/net_wins.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NET_WINS_H
|
||||
#define NET_WINS_H
|
||||
|
||||
int WINS_Init(void);
|
||||
void WINS_Shutdown(void);
|
||||
void WINS_Listen(qboolean state);
|
||||
int WINS_OpenSocket(int port);
|
||||
int WINS_CloseSocket(int socket);
|
||||
int WINS_Connect(int socket, struct qsockaddr *addr);
|
||||
int WINS_CheckNewConnections(void);
|
||||
int WINS_Read(int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int WINS_Write(int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int WINS_Broadcast(int socket, byte *buf, int len);
|
||||
char *WINS_AddrToString(struct qsockaddr *addr);
|
||||
int WINS_StringToAddr(char *string, struct qsockaddr *addr);
|
||||
int WINS_GetSocketAddr(int socket, struct qsockaddr *addr);
|
||||
int WINS_GetNameFromAddr(struct qsockaddr *addr, char *name);
|
||||
int WINS_GetAddrFromName(char *name, struct qsockaddr *addr);
|
||||
int WINS_AddrCompare(struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||
int WINS_GetSocketPort(struct qsockaddr *addr);
|
||||
int WINS_SetSocketPort(struct qsockaddr *addr, int port);
|
||||
|
||||
#endif /* NET_WINS_H */
|
467
NQ/net_wipx.c
Normal file
467
NQ/net_wipx.c
Normal file
@ -0,0 +1,467 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_wipx.c
|
||||
|
||||
#include "console.h"
|
||||
#include "net.h"
|
||||
#include "quakedef.h"
|
||||
#include "sys.h"
|
||||
#include "winquake.h"
|
||||
|
||||
/* Needs to be after winquake.h?? - FIXME (remove it) */
|
||||
#include <wsipx.h>
|
||||
|
||||
#include "net_wipx.h"
|
||||
|
||||
/*
|
||||
// FIXME - End fix for missing wsipx.h in MinGW?
|
||||
struct sockaddr_ipx {
|
||||
short sa_family;
|
||||
char sa_netnum[4];
|
||||
char sa_nodenum[6];
|
||||
unsigned short sa_socket;
|
||||
};
|
||||
#define NSPROTO_IPX 1000
|
||||
*/
|
||||
|
||||
#include "net_wipx.h"
|
||||
|
||||
static int net_acceptsocket = -1; // socket for fielding new connections
|
||||
static int net_controlsocket;
|
||||
static struct qsockaddr broadcastaddr;
|
||||
|
||||
#define IPXSOCKETS 18
|
||||
static int ipxsocket[IPXSOCKETS];
|
||||
static int sequence[IPXSOCKETS];
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_Init(void)
|
||||
{
|
||||
int i;
|
||||
char buff[MAXHOSTNAMELEN];
|
||||
struct qsockaddr addr;
|
||||
char *p;
|
||||
int r;
|
||||
WORD wVersionRequested;
|
||||
|
||||
if (COM_CheckParm("-noipx"))
|
||||
return -1;
|
||||
|
||||
// make sure LoadLibrary has happened successfully
|
||||
if (!winsock_lib_initialized)
|
||||
return -1;
|
||||
|
||||
if (winsock_initialized == 0) {
|
||||
wVersionRequested = MAKEWORD(1, 1);
|
||||
|
||||
r = pWSAStartup(MAKEWORD(1, 1), &winsockdata);
|
||||
|
||||
if (r) {
|
||||
Con_Printf("Winsock initialization failed.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
winsock_initialized++;
|
||||
|
||||
for (i = 0; i < IPXSOCKETS; i++)
|
||||
ipxsocket[i] = 0;
|
||||
|
||||
// determine my name & address
|
||||
if (pgethostname(buff, MAXHOSTNAMELEN) == 0) {
|
||||
// if the quake hostname isn't set, set it to the machine name
|
||||
if (strcmp(hostname.string, "UNNAMED") == 0) {
|
||||
// see if it's a text IP address (well, close enough)
|
||||
for (p = buff; *p; p++)
|
||||
if ((*p < '0' || *p > '9') && *p != '.')
|
||||
break;
|
||||
|
||||
// if it is a real name, strip off the domain; we only want the host
|
||||
if (*p) {
|
||||
for (i = 0; i < 15; i++)
|
||||
if (buff[i] == '.')
|
||||
break;
|
||||
buff[i] = 0;
|
||||
}
|
||||
Cvar_Set("hostname", buff);
|
||||
}
|
||||
}
|
||||
|
||||
if ((net_controlsocket = WIPX_OpenSocket(0)) == -1) {
|
||||
Con_Printf("WIPX_Init: Unable to open control socket\n");
|
||||
if (--winsock_initialized == 0)
|
||||
pWSACleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
((struct sockaddr_ipx *)&broadcastaddr)->sa_family = AF_IPX;
|
||||
memset(((struct sockaddr_ipx *)&broadcastaddr)->sa_netnum, 0, 4);
|
||||
memset(((struct sockaddr_ipx *)&broadcastaddr)->sa_nodenum, 0xff, 6);
|
||||
((struct sockaddr_ipx *)&broadcastaddr)->sa_socket =
|
||||
htons((unsigned short)net_hostport);
|
||||
|
||||
WIPX_GetSocketAddr(net_controlsocket, &addr);
|
||||
strcpy(my_ipx_address, WIPX_AddrToString(&addr));
|
||||
p = strrchr(my_ipx_address, ':');
|
||||
if (p)
|
||||
*p = 0;
|
||||
|
||||
Con_Printf("Winsock IPX Initialized\n");
|
||||
ipxAvailable = true;
|
||||
|
||||
return net_controlsocket;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void
|
||||
WIPX_Shutdown(void)
|
||||
{
|
||||
WIPX_Listen(false);
|
||||
WIPX_CloseSocket(net_controlsocket);
|
||||
if (--winsock_initialized == 0)
|
||||
pWSACleanup();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void
|
||||
WIPX_Listen(qboolean state)
|
||||
{
|
||||
// enable listening
|
||||
if (state) {
|
||||
if (net_acceptsocket != -1)
|
||||
return;
|
||||
if ((net_acceptsocket = WIPX_OpenSocket(net_hostport)) == -1)
|
||||
Sys_Error("%s: Unable to open accept socket", __func__);
|
||||
return;
|
||||
}
|
||||
// disable listening
|
||||
if (net_acceptsocket == -1)
|
||||
return;
|
||||
WIPX_CloseSocket(net_acceptsocket);
|
||||
net_acceptsocket = -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_OpenSocket(int port)
|
||||
{
|
||||
int handle;
|
||||
int newsocket;
|
||||
struct sockaddr_ipx address;
|
||||
u_long _true = 1;
|
||||
|
||||
for (handle = 0; handle < IPXSOCKETS; handle++)
|
||||
if (ipxsocket[handle] == 0)
|
||||
break;
|
||||
if (handle == IPXSOCKETS)
|
||||
return -1;
|
||||
|
||||
if ((newsocket =
|
||||
psocket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == INVALID_SOCKET)
|
||||
return -1;
|
||||
|
||||
if (pioctlsocket(newsocket, FIONBIO, &_true) == -1)
|
||||
goto ErrorReturn;
|
||||
|
||||
if (psetsockopt
|
||||
(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true,
|
||||
sizeof(_true)) < 0)
|
||||
goto ErrorReturn;
|
||||
|
||||
address.sa_family = AF_IPX;
|
||||
memset(address.sa_netnum, 0, 4);
|
||||
memset(address.sa_nodenum, 0, 6);;
|
||||
address.sa_socket = htons((unsigned short)port);
|
||||
if (bind(newsocket, (void *)&address, sizeof(address)) == 0) {
|
||||
ipxsocket[handle] = newsocket;
|
||||
sequence[handle] = 0;
|
||||
return handle;
|
||||
}
|
||||
|
||||
Sys_Error("Winsock IPX bind failed");
|
||||
ErrorReturn:
|
||||
pclosesocket(newsocket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_CloseSocket(int handle)
|
||||
{
|
||||
int socket = ipxsocket[handle];
|
||||
int ret;
|
||||
|
||||
ret = pclosesocket(socket);
|
||||
ipxsocket[handle] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_Connect(int handle, struct qsockaddr *addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_CheckNewConnections(void)
|
||||
{
|
||||
unsigned long available;
|
||||
|
||||
if (net_acceptsocket == -1)
|
||||
return -1;
|
||||
|
||||
if (pioctlsocket(ipxsocket[net_acceptsocket], FIONREAD, &available) == -1)
|
||||
Sys_Error("%s: ioctlsocket (FIONREAD) failed", __func__);
|
||||
if (available)
|
||||
return net_acceptsocket;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
static byte packetBuffer[NET_DATAGRAMSIZE + 4];
|
||||
|
||||
int
|
||||
WIPX_Read(int handle, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
int addrlen = sizeof(struct qsockaddr);
|
||||
int socket = ipxsocket[handle];
|
||||
int ret;
|
||||
|
||||
ret =
|
||||
precvfrom(socket, packetBuffer, len + 4, 0, (struct sockaddr *)addr,
|
||||
&addrlen);
|
||||
if (ret == -1) {
|
||||
int err = pWSAGetLastError();
|
||||
|
||||
if (err == WSAEWOULDBLOCK || err == WSAECONNREFUSED)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (ret < 4)
|
||||
return 0;
|
||||
|
||||
// remove sequence number, it's only needed for DOS IPX
|
||||
ret -= 4;
|
||||
memcpy(buf, packetBuffer + 4, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_Broadcast(int handle, byte *buf, int len)
|
||||
{
|
||||
return WIPX_Write(handle, buf, len, &broadcastaddr);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_Write(int handle, byte *buf, int len, struct qsockaddr *addr)
|
||||
{
|
||||
int socket = ipxsocket[handle];
|
||||
int ret;
|
||||
|
||||
// build packet with sequence number
|
||||
*(int *)(&packetBuffer[0]) = sequence[handle];
|
||||
sequence[handle]++;
|
||||
memcpy(&packetBuffer[4], buf, len);
|
||||
len += 4;
|
||||
|
||||
ret =
|
||||
psendto(socket, packetBuffer, len, 0, (struct sockaddr *)addr,
|
||||
sizeof(struct qsockaddr));
|
||||
if (ret == -1)
|
||||
if (pWSAGetLastError() == WSAEWOULDBLOCK)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
char *
|
||||
WIPX_AddrToString(struct qsockaddr *addr)
|
||||
{
|
||||
static char buf[28];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_StringToAddr(char *string, struct qsockaddr *addr)
|
||||
{
|
||||
int val;
|
||||
char buf[3];
|
||||
|
||||
buf[2] = 0;
|
||||
memset(addr, 0, sizeof(struct qsockaddr));
|
||||
addr->sa_family = AF_IPX;
|
||||
|
||||
#define DO(src,dest) \
|
||||
buf[0] = string[src]; \
|
||||
buf[1] = string[src + 1]; \
|
||||
if (sscanf (buf, "%x", &val) != 1) \
|
||||
return -1; \
|
||||
((struct sockaddr_ipx *)addr)->dest = val
|
||||
|
||||
DO(0, sa_netnum[0]);
|
||||
DO(2, sa_netnum[1]);
|
||||
DO(4, sa_netnum[2]);
|
||||
DO(6, sa_netnum[3]);
|
||||
DO(9, sa_nodenum[0]);
|
||||
DO(11, sa_nodenum[1]);
|
||||
DO(13, sa_nodenum[2]);
|
||||
DO(15, sa_nodenum[3]);
|
||||
DO(17, sa_nodenum[4]);
|
||||
DO(19, sa_nodenum[5]);
|
||||
#undef DO
|
||||
|
||||
sscanf(&string[22], "%u", &val);
|
||||
((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_GetSocketAddr(int handle, struct qsockaddr *addr)
|
||||
{
|
||||
int socket = ipxsocket[handle];
|
||||
int addrlen = sizeof(struct qsockaddr);
|
||||
|
||||
memset(addr, 0, sizeof(struct qsockaddr));
|
||||
if (pgetsockname(socket, (struct sockaddr *)addr, &addrlen) != 0) {
|
||||
int err = pWSAGetLastError();
|
||||
|
||||
// FIXME - hack to get rid of unused warning
|
||||
// - find out what should really be done
|
||||
if (err)
|
||||
err = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_GetNameFromAddr(struct qsockaddr *addr, char *name)
|
||||
{
|
||||
strcpy(name, WIPX_AddrToString(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_GetAddrFromName(char *name, struct qsockaddr *addr)
|
||||
{
|
||||
int n;
|
||||
char buf[32];
|
||||
|
||||
n = strlen(name);
|
||||
|
||||
if (n == 12) {
|
||||
sprintf(buf, "00000000:%s:%u", name, net_hostport);
|
||||
return WIPX_StringToAddr(buf, addr);
|
||||
}
|
||||
if (n == 21) {
|
||||
sprintf(buf, "%s:%u", name, net_hostport);
|
||||
return WIPX_StringToAddr(buf, addr);
|
||||
}
|
||||
if (n > 21 && n <= 27)
|
||||
return WIPX_StringToAddr(name, addr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_AddrCompare(struct qsockaddr *addr1, struct qsockaddr *addr2)
|
||||
{
|
||||
if (addr1->sa_family != addr2->sa_family)
|
||||
return -1;
|
||||
|
||||
if (*((struct sockaddr_ipx *)addr1)->sa_netnum
|
||||
&& *((struct sockaddr_ipx *)addr2)->sa_netnum)
|
||||
if (memcmp
|
||||
(((struct sockaddr_ipx *)addr1)->sa_netnum,
|
||||
((struct sockaddr_ipx *)addr2)->sa_netnum, 4) != 0)
|
||||
return -1;
|
||||
if (memcmp
|
||||
(((struct sockaddr_ipx *)addr1)->sa_nodenum,
|
||||
((struct sockaddr_ipx *)addr2)->sa_nodenum, 6) != 0)
|
||||
return -1;
|
||||
|
||||
if (((struct sockaddr_ipx *)addr1)->sa_socket !=
|
||||
((struct sockaddr_ipx *)addr2)->sa_socket)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
int
|
||||
WIPX_GetSocketPort(struct qsockaddr *addr)
|
||||
{
|
||||
return ntohs(((struct sockaddr_ipx *)addr)->sa_socket);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
WIPX_SetSocketPort(struct qsockaddr *addr, int port)
|
||||
{
|
||||
((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
47
NQ/net_wipx.h
Normal file
47
NQ/net_wipx.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NET_WIPX_H
|
||||
#define NET_WIPX_H
|
||||
|
||||
// net_wipx.h
|
||||
|
||||
#include "net.h"
|
||||
|
||||
int WIPX_Init(void);
|
||||
void WIPX_Shutdown(void);
|
||||
void WIPX_Listen(qboolean state);
|
||||
int WIPX_OpenSocket(int port);
|
||||
int WIPX_CloseSocket(int socket);
|
||||
int WIPX_Connect(int socket, struct qsockaddr *addr);
|
||||
int WIPX_CheckNewConnections(void);
|
||||
int WIPX_Read(int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int WIPX_Write(int socket, byte *buf, int len, struct qsockaddr *addr);
|
||||
int WIPX_Broadcast(int socket, byte *buf, int len);
|
||||
char *WIPX_AddrToString(struct qsockaddr *addr);
|
||||
int WIPX_StringToAddr(char *string, struct qsockaddr *addr);
|
||||
int WIPX_GetSocketAddr(int socket, struct qsockaddr *addr);
|
||||
int WIPX_GetNameFromAddr(struct qsockaddr *addr, char *name);
|
||||
int WIPX_GetAddrFromName(char *name, struct qsockaddr *addr);
|
||||
int WIPX_AddrCompare(struct qsockaddr *addr1, struct qsockaddr *addr2);
|
||||
int WIPX_GetSocketPort(struct qsockaddr *addr);
|
||||
int WIPX_SetSocketPort(struct qsockaddr *addr, int port);
|
||||
|
||||
#endif /* NET_WIPX_H */
|
1668
NQ/pr_cmds.c
Normal file
1668
NQ/pr_cmds.c
Normal file
File diff suppressed because it is too large
Load Diff
1119
NQ/pr_edict.c
Normal file
1119
NQ/pr_edict.c
Normal file
File diff suppressed because it is too large
Load Diff
659
NQ/pr_exec.c
Normal file
659
NQ/pr_exec.c
Normal file
@ -0,0 +1,659 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "host.h"
|
||||
#include "pr_comp.h"
|
||||
#include "console.h"
|
||||
#include "progs.h"
|
||||
#include "server.h"
|
||||
#include "sys.h"
|
||||
|
||||
typedef struct {
|
||||
int s;
|
||||
dfunction_t *f;
|
||||
} prstack_t;
|
||||
|
||||
#define MAX_STACK_DEPTH 32
|
||||
prstack_t pr_stack[MAX_STACK_DEPTH];
|
||||
int pr_depth;
|
||||
|
||||
#define LOCALSTACK_SIZE 2048
|
||||
int localstack[LOCALSTACK_SIZE];
|
||||
int localstack_used;
|
||||
|
||||
qboolean pr_trace;
|
||||
dfunction_t *pr_xfunction;
|
||||
int pr_xstatement;
|
||||
|
||||
int pr_argc;
|
||||
|
||||
char *pr_opnames[] = {
|
||||
"DONE",
|
||||
|
||||
"MUL_F",
|
||||
"MUL_V",
|
||||
"MUL_FV",
|
||||
"MUL_VF",
|
||||
|
||||
"DIV",
|
||||
|
||||
"ADD_F",
|
||||
"ADD_V",
|
||||
|
||||
"SUB_F",
|
||||
"SUB_V",
|
||||
|
||||
"EQ_F",
|
||||
"EQ_V",
|
||||
"EQ_S",
|
||||
"EQ_E",
|
||||
"EQ_FNC",
|
||||
|
||||
"NE_F",
|
||||
"NE_V",
|
||||
"NE_S",
|
||||
"NE_E",
|
||||
"NE_FNC",
|
||||
|
||||
"LE",
|
||||
"GE",
|
||||
"LT",
|
||||
"GT",
|
||||
|
||||
"INDIRECT",
|
||||
"INDIRECT",
|
||||
"INDIRECT",
|
||||
"INDIRECT",
|
||||
"INDIRECT",
|
||||
"INDIRECT",
|
||||
|
||||
"ADDRESS",
|
||||
|
||||
"STORE_F",
|
||||
"STORE_V",
|
||||
"STORE_S",
|
||||
"STORE_ENT",
|
||||
"STORE_FLD",
|
||||
"STORE_FNC",
|
||||
|
||||
"STOREP_F",
|
||||
"STOREP_V",
|
||||
"STOREP_S",
|
||||
"STOREP_ENT",
|
||||
"STOREP_FLD",
|
||||
"STOREP_FNC",
|
||||
|
||||
"RETURN",
|
||||
|
||||
"NOT_F",
|
||||
"NOT_V",
|
||||
"NOT_S",
|
||||
"NOT_ENT",
|
||||
"NOT_FNC",
|
||||
|
||||
"IF",
|
||||
"IFNOT",
|
||||
|
||||
"CALL0",
|
||||
"CALL1",
|
||||
"CALL2",
|
||||
"CALL3",
|
||||
"CALL4",
|
||||
"CALL5",
|
||||
"CALL6",
|
||||
"CALL7",
|
||||
"CALL8",
|
||||
|
||||
"STATE",
|
||||
|
||||
"GOTO",
|
||||
|
||||
"AND",
|
||||
"OR",
|
||||
|
||||
"BITAND",
|
||||
"BITOR"
|
||||
};
|
||||
|
||||
char *PR_GlobalString(int ofs);
|
||||
char *PR_GlobalStringNoContents(int ofs);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
=================
|
||||
PR_PrintStatement
|
||||
=================
|
||||
*/
|
||||
void
|
||||
PR_PrintStatement(dstatement_t *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((unsigned)s->op < sizeof(pr_opnames) / sizeof(pr_opnames[0])) {
|
||||
Con_Printf("%s ", pr_opnames[s->op]);
|
||||
i = strlen(pr_opnames[s->op]);
|
||||
for (; i < 10; i++)
|
||||
Con_Printf(" ");
|
||||
}
|
||||
|
||||
if (s->op == OP_IF || s->op == OP_IFNOT)
|
||||
Con_Printf("%sbranch %i", PR_GlobalString(s->a), s->b);
|
||||
else if (s->op == OP_GOTO) {
|
||||
Con_Printf("branch %i", s->a);
|
||||
} else if ((unsigned)(s->op - OP_STORE_F) < 6) {
|
||||
Con_Printf("%s", PR_GlobalString(s->a));
|
||||
Con_Printf("%s", PR_GlobalStringNoContents(s->b));
|
||||
} else {
|
||||
if (s->a)
|
||||
Con_Printf("%s", PR_GlobalString(s->a));
|
||||
if (s->b)
|
||||
Con_Printf("%s", PR_GlobalString(s->b));
|
||||
if (s->c)
|
||||
Con_Printf("%s", PR_GlobalStringNoContents(s->c));
|
||||
}
|
||||
Con_Printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
PR_StackTrace
|
||||
============
|
||||
*/
|
||||
void
|
||||
PR_StackTrace(void)
|
||||
{
|
||||
dfunction_t *f;
|
||||
int i;
|
||||
|
||||
if (pr_depth == 0) {
|
||||
Con_Printf("<NO STACK>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pr_stack[pr_depth].f = pr_xfunction;
|
||||
for (i = pr_depth; i >= 0; i--) {
|
||||
f = pr_stack[i].f;
|
||||
if (!f)
|
||||
Con_Printf("<NO FUNCTION>\n");
|
||||
else
|
||||
Con_Printf("%12s : %s\n", pr_strings + f->s_file,
|
||||
pr_strings + f->s_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
PR_Profile_f
|
||||
|
||||
============
|
||||
*/
|
||||
void
|
||||
PR_Profile_f(void)
|
||||
{
|
||||
dfunction_t *f, *best;
|
||||
int max;
|
||||
int num;
|
||||
int i;
|
||||
|
||||
// FIXME - progs get unloaded? if so, check that progs gets zero'd
|
||||
if (!progs)
|
||||
return;
|
||||
|
||||
num = 0;
|
||||
do {
|
||||
max = 0;
|
||||
best = NULL;
|
||||
for (i = 0; i < progs->numfunctions; i++) {
|
||||
f = &pr_functions[i];
|
||||
if (f->profile > max) {
|
||||
max = f->profile;
|
||||
best = f;
|
||||
}
|
||||
}
|
||||
if (best) {
|
||||
if (num < 10)
|
||||
Con_Printf("%7i %s\n", best->profile,
|
||||
pr_strings + best->s_name);
|
||||
num++;
|
||||
best->profile = 0;
|
||||
}
|
||||
} while (best);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
PR_RunError
|
||||
|
||||
Aborts the currently executing function
|
||||
============
|
||||
*/
|
||||
void
|
||||
PR_RunError(char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
va_start(argptr, error);
|
||||
vsprintf(string, error, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
PR_PrintStatement(pr_statements + pr_xstatement);
|
||||
PR_StackTrace();
|
||||
Con_Printf("%s\n", string);
|
||||
|
||||
pr_depth = 0; // dump the stack so host_error can shutdown functions
|
||||
|
||||
Host_Error("Program error");
|
||||
}
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
PR_ExecuteProgram
|
||||
|
||||
The interpretation main loop
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
====================
|
||||
PR_EnterFunction
|
||||
|
||||
Returns the new program statement counter
|
||||
====================
|
||||
*/
|
||||
int
|
||||
PR_EnterFunction(dfunction_t *f)
|
||||
{
|
||||
int i, j, c, o;
|
||||
|
||||
pr_stack[pr_depth].s = pr_xstatement;
|
||||
pr_stack[pr_depth].f = pr_xfunction;
|
||||
pr_depth++;
|
||||
if (pr_depth >= MAX_STACK_DEPTH)
|
||||
PR_RunError("stack overflow");
|
||||
|
||||
// save off any locals that the new function steps on
|
||||
c = f->locals;
|
||||
if (localstack_used + c > LOCALSTACK_SIZE)
|
||||
PR_RunError("PR_ExecuteProgram: locals stack overflow\n");
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
localstack[localstack_used + i] =
|
||||
((int *)pr_globals)[f->parm_start + i];
|
||||
localstack_used += c;
|
||||
|
||||
// copy parameters
|
||||
o = f->parm_start;
|
||||
for (i = 0; i < f->numparms; i++) {
|
||||
for (j = 0; j < f->parm_size[i]; j++) {
|
||||
((int *)pr_globals)[o] =
|
||||
((int *)pr_globals)[OFS_PARM0 + i * 3 + j];
|
||||
o++;
|
||||
}
|
||||
}
|
||||
|
||||
pr_xfunction = f;
|
||||
return f->first_statement - 1; // offset the s++
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
PR_LeaveFunction
|
||||
====================
|
||||
*/
|
||||
int
|
||||
PR_LeaveFunction(void)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
if (pr_depth <= 0)
|
||||
Sys_Error("prog stack underflow");
|
||||
|
||||
// restore locals from the stack
|
||||
c = pr_xfunction->locals;
|
||||
localstack_used -= c;
|
||||
if (localstack_used < 0)
|
||||
PR_RunError("PR_ExecuteProgram: locals stack underflow\n");
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
((int *)pr_globals)[pr_xfunction->parm_start + i] =
|
||||
localstack[localstack_used + i];
|
||||
|
||||
// up stack
|
||||
pr_depth--;
|
||||
pr_xfunction = pr_stack[pr_depth].f;
|
||||
return pr_stack[pr_depth].s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
PR_ExecuteProgram
|
||||
====================
|
||||
*/
|
||||
void
|
||||
PR_ExecuteProgram(func_t fnum)
|
||||
{
|
||||
eval_t *a, *b, *c;
|
||||
int s;
|
||||
dstatement_t *st;
|
||||
dfunction_t *f, *newf;
|
||||
int runaway;
|
||||
int i;
|
||||
edict_t *ed;
|
||||
int exitdepth;
|
||||
eval_t *ptr;
|
||||
|
||||
if (!fnum || fnum >= progs->numfunctions) {
|
||||
if (pr_global_struct->self)
|
||||
ED_Print(PROG_TO_EDICT(pr_global_struct->self));
|
||||
Host_Error("PR_ExecuteProgram: NULL function");
|
||||
}
|
||||
|
||||
f = &pr_functions[fnum];
|
||||
|
||||
runaway = 100000;
|
||||
pr_trace = false;
|
||||
|
||||
// make a stack frame
|
||||
exitdepth = pr_depth;
|
||||
|
||||
s = PR_EnterFunction(f);
|
||||
|
||||
while (1) {
|
||||
s++; // next statement
|
||||
|
||||
st = &pr_statements[s];
|
||||
a = (eval_t *)&pr_globals[st->a];
|
||||
b = (eval_t *)&pr_globals[st->b];
|
||||
c = (eval_t *)&pr_globals[st->c];
|
||||
|
||||
if (!--runaway)
|
||||
PR_RunError("runaway loop error");
|
||||
if (runaway <= 50000 && !(runaway % 5000))
|
||||
Con_DPrintf("%s: progs execution running away (%i left)\n",
|
||||
__func__, runaway);
|
||||
|
||||
pr_xfunction->profile++;
|
||||
pr_xstatement = s;
|
||||
|
||||
if (pr_trace)
|
||||
PR_PrintStatement(st);
|
||||
|
||||
switch (st->op) {
|
||||
case OP_ADD_F:
|
||||
c->_float = a->_float + b->_float;
|
||||
break;
|
||||
case OP_ADD_V:
|
||||
c->vector[0] = a->vector[0] + b->vector[0];
|
||||
c->vector[1] = a->vector[1] + b->vector[1];
|
||||
c->vector[2] = a->vector[2] + b->vector[2];
|
||||
break;
|
||||
|
||||
case OP_SUB_F:
|
||||
c->_float = a->_float - b->_float;
|
||||
break;
|
||||
case OP_SUB_V:
|
||||
c->vector[0] = a->vector[0] - b->vector[0];
|
||||
c->vector[1] = a->vector[1] - b->vector[1];
|
||||
c->vector[2] = a->vector[2] - b->vector[2];
|
||||
break;
|
||||
|
||||
case OP_MUL_F:
|
||||
c->_float = a->_float * b->_float;
|
||||
break;
|
||||
case OP_MUL_V:
|
||||
c->_float = a->vector[0] * b->vector[0]
|
||||
+ a->vector[1] * b->vector[1]
|
||||
+ a->vector[2] * b->vector[2];
|
||||
break;
|
||||
case OP_MUL_FV:
|
||||
c->vector[0] = a->_float * b->vector[0];
|
||||
c->vector[1] = a->_float * b->vector[1];
|
||||
c->vector[2] = a->_float * b->vector[2];
|
||||
break;
|
||||
case OP_MUL_VF:
|
||||
c->vector[0] = b->_float * a->vector[0];
|
||||
c->vector[1] = b->_float * a->vector[1];
|
||||
c->vector[2] = b->_float * a->vector[2];
|
||||
break;
|
||||
|
||||
case OP_DIV_F:
|
||||
c->_float = a->_float / b->_float;
|
||||
break;
|
||||
|
||||
case OP_BITAND:
|
||||
c->_float = (int)a->_float & (int)b->_float;
|
||||
break;
|
||||
|
||||
case OP_BITOR:
|
||||
c->_float = (int)a->_float | (int)b->_float;
|
||||
break;
|
||||
|
||||
|
||||
case OP_GE:
|
||||
c->_float = a->_float >= b->_float;
|
||||
break;
|
||||
case OP_LE:
|
||||
c->_float = a->_float <= b->_float;
|
||||
break;
|
||||
case OP_GT:
|
||||
c->_float = a->_float > b->_float;
|
||||
break;
|
||||
case OP_LT:
|
||||
c->_float = a->_float < b->_float;
|
||||
break;
|
||||
case OP_AND:
|
||||
c->_float = a->_float && b->_float;
|
||||
break;
|
||||
case OP_OR:
|
||||
c->_float = a->_float || b->_float;
|
||||
break;
|
||||
|
||||
case OP_NOT_F:
|
||||
c->_float = !a->_float;
|
||||
break;
|
||||
case OP_NOT_V:
|
||||
c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2];
|
||||
break;
|
||||
case OP_NOT_S:
|
||||
c->_float = !a->string || !pr_strings[a->string];
|
||||
break;
|
||||
case OP_NOT_FNC:
|
||||
c->_float = !a->function;
|
||||
break;
|
||||
case OP_NOT_ENT:
|
||||
c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts);
|
||||
break;
|
||||
|
||||
case OP_EQ_F:
|
||||
c->_float = a->_float == b->_float;
|
||||
break;
|
||||
case OP_EQ_V:
|
||||
c->_float = (a->vector[0] == b->vector[0]) &&
|
||||
(a->vector[1] == b->vector[1]) &&
|
||||
(a->vector[2] == b->vector[2]);
|
||||
break;
|
||||
case OP_EQ_S:
|
||||
c->_float =
|
||||
!strcmp(pr_strings + a->string, pr_strings + b->string);
|
||||
break;
|
||||
case OP_EQ_E:
|
||||
c->_float = a->_int == b->_int;
|
||||
break;
|
||||
case OP_EQ_FNC:
|
||||
c->_float = a->function == b->function;
|
||||
break;
|
||||
|
||||
case OP_NE_F:
|
||||
c->_float = a->_float != b->_float;
|
||||
break;
|
||||
case OP_NE_V:
|
||||
c->_float = (a->vector[0] != b->vector[0]) ||
|
||||
(a->vector[1] != b->vector[1]) ||
|
||||
(a->vector[2] != b->vector[2]);
|
||||
break;
|
||||
case OP_NE_S:
|
||||
c->_float =
|
||||
strcmp(pr_strings + a->string, pr_strings + b->string);
|
||||
break;
|
||||
case OP_NE_E:
|
||||
c->_float = a->_int != b->_int;
|
||||
break;
|
||||
case OP_NE_FNC:
|
||||
c->_float = a->function != b->function;
|
||||
break;
|
||||
|
||||
//==================
|
||||
case OP_STORE_F:
|
||||
case OP_STORE_ENT:
|
||||
case OP_STORE_FLD: // integers
|
||||
case OP_STORE_S:
|
||||
case OP_STORE_FNC: // pointers
|
||||
b->_int = a->_int;
|
||||
break;
|
||||
case OP_STORE_V:
|
||||
b->vector[0] = a->vector[0];
|
||||
b->vector[1] = a->vector[1];
|
||||
b->vector[2] = a->vector[2];
|
||||
break;
|
||||
|
||||
case OP_STOREP_F:
|
||||
case OP_STOREP_ENT:
|
||||
case OP_STOREP_FLD: // integers
|
||||
case OP_STOREP_S:
|
||||
case OP_STOREP_FNC: // pointers
|
||||
ptr = (eval_t *)((byte *)sv.edicts + b->_int);
|
||||
ptr->_int = a->_int;
|
||||
break;
|
||||
case OP_STOREP_V:
|
||||
ptr = (eval_t *)((byte *)sv.edicts + b->_int);
|
||||
ptr->vector[0] = a->vector[0];
|
||||
ptr->vector[1] = a->vector[1];
|
||||
ptr->vector[2] = a->vector[2];
|
||||
break;
|
||||
|
||||
case OP_ADDRESS:
|
||||
ed = PROG_TO_EDICT(a->edict);
|
||||
#ifdef PARANOID
|
||||
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||
#endif
|
||||
if (ed == (edict_t *)sv.edicts && sv.state == ss_active)
|
||||
PR_RunError("assignment to world entity");
|
||||
c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts;
|
||||
break;
|
||||
|
||||
case OP_LOAD_F:
|
||||
case OP_LOAD_FLD:
|
||||
case OP_LOAD_ENT:
|
||||
case OP_LOAD_S:
|
||||
case OP_LOAD_FNC:
|
||||
ed = PROG_TO_EDICT(a->edict);
|
||||
#ifdef PARANOID
|
||||
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||
#endif
|
||||
a = (eval_t *)((int *)&ed->v + b->_int);
|
||||
c->_int = a->_int;
|
||||
break;
|
||||
|
||||
case OP_LOAD_V:
|
||||
ed = PROG_TO_EDICT(a->edict);
|
||||
#ifdef PARANOID
|
||||
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||
#endif
|
||||
a = (eval_t *)((int *)&ed->v + b->_int);
|
||||
c->vector[0] = a->vector[0];
|
||||
c->vector[1] = a->vector[1];
|
||||
c->vector[2] = a->vector[2];
|
||||
break;
|
||||
|
||||
//==================
|
||||
|
||||
case OP_IFNOT:
|
||||
if (!a->_int)
|
||||
s += st->b - 1; // offset the s++
|
||||
break;
|
||||
|
||||
case OP_IF:
|
||||
if (a->_int)
|
||||
s += st->b - 1; // offset the s++
|
||||
break;
|
||||
|
||||
case OP_GOTO:
|
||||
s += st->a - 1; // offset the s++
|
||||
break;
|
||||
|
||||
case OP_CALL0:
|
||||
case OP_CALL1:
|
||||
case OP_CALL2:
|
||||
case OP_CALL3:
|
||||
case OP_CALL4:
|
||||
case OP_CALL5:
|
||||
case OP_CALL6:
|
||||
case OP_CALL7:
|
||||
case OP_CALL8:
|
||||
pr_argc = st->op - OP_CALL0;
|
||||
if (!a->function)
|
||||
PR_RunError("NULL function");
|
||||
|
||||
newf = &pr_functions[a->function];
|
||||
|
||||
/* negative statements are built in functions */
|
||||
if (newf->first_statement < 0) {
|
||||
i = -newf->first_statement;
|
||||
if (i >= pr_numbuiltins)
|
||||
PR_RunError("Bad builtin call number");
|
||||
pr_builtins[i] ();
|
||||
break;
|
||||
}
|
||||
|
||||
s = PR_EnterFunction(newf);
|
||||
break;
|
||||
|
||||
case OP_DONE:
|
||||
case OP_RETURN:
|
||||
pr_globals[OFS_RETURN] = pr_globals[st->a];
|
||||
pr_globals[OFS_RETURN + 1] = pr_globals[st->a + 1];
|
||||
pr_globals[OFS_RETURN + 2] = pr_globals[st->a + 2];
|
||||
|
||||
s = PR_LeaveFunction();
|
||||
if (pr_depth == exitdepth)
|
||||
return; // all done
|
||||
break;
|
||||
|
||||
case OP_STATE:
|
||||
ed = PROG_TO_EDICT(pr_global_struct->self);
|
||||
ed->v.nextthink = pr_global_struct->time + 0.1;
|
||||
if (a->_float != ed->v.frame) {
|
||||
ed->v.frame = a->_float;
|
||||
}
|
||||
ed->v.think = b->function;
|
||||
break;
|
||||
|
||||
default:
|
||||
PR_RunError("Bad opcode %i", st->op);
|
||||
}
|
||||
}
|
||||
}
|
27
NQ/progdefs.h
Normal file
27
NQ/progdefs.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PROGDEFS_H
|
||||
#define PROGDEFS_H
|
||||
|
||||
#include "mathlib.h"
|
||||
#include "progdefs.q1"
|
||||
|
||||
#endif /* PROGDEFS_H */
|
143
NQ/progdefs.q1
Normal file
143
NQ/progdefs.q1
Normal file
@ -0,0 +1,143 @@
|
||||
|
||||
/* file generated by qcc, do not modify */
|
||||
|
||||
typedef struct
|
||||
{ int pad[28];
|
||||
int self;
|
||||
int other;
|
||||
int world;
|
||||
float time;
|
||||
float frametime;
|
||||
float force_retouch;
|
||||
string_t mapname;
|
||||
float deathmatch;
|
||||
float coop;
|
||||
float teamplay;
|
||||
float serverflags;
|
||||
float total_secrets;
|
||||
float total_monsters;
|
||||
float found_secrets;
|
||||
float killed_monsters;
|
||||
float parm1;
|
||||
float parm2;
|
||||
float parm3;
|
||||
float parm4;
|
||||
float parm5;
|
||||
float parm6;
|
||||
float parm7;
|
||||
float parm8;
|
||||
float parm9;
|
||||
float parm10;
|
||||
float parm11;
|
||||
float parm12;
|
||||
float parm13;
|
||||
float parm14;
|
||||
float parm15;
|
||||
float parm16;
|
||||
vec3_t v_forward;
|
||||
vec3_t v_up;
|
||||
vec3_t v_right;
|
||||
float trace_allsolid;
|
||||
float trace_startsolid;
|
||||
float trace_fraction;
|
||||
vec3_t trace_endpos;
|
||||
vec3_t trace_plane_normal;
|
||||
float trace_plane_dist;
|
||||
int trace_ent;
|
||||
float trace_inopen;
|
||||
float trace_inwater;
|
||||
int msg_entity;
|
||||
func_t main;
|
||||
func_t StartFrame;
|
||||
func_t PlayerPreThink;
|
||||
func_t PlayerPostThink;
|
||||
func_t ClientKill;
|
||||
func_t ClientConnect;
|
||||
func_t PutClientInServer;
|
||||
func_t ClientDisconnect;
|
||||
func_t SetNewParms;
|
||||
func_t SetChangeParms;
|
||||
} globalvars_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float modelindex;
|
||||
vec3_t absmin;
|
||||
vec3_t absmax;
|
||||
float ltime;
|
||||
float movetype;
|
||||
float solid;
|
||||
vec3_t origin;
|
||||
vec3_t oldorigin;
|
||||
vec3_t velocity;
|
||||
vec3_t angles;
|
||||
vec3_t avelocity;
|
||||
vec3_t punchangle;
|
||||
string_t classname;
|
||||
string_t model;
|
||||
float frame;
|
||||
float skin;
|
||||
float effects;
|
||||
vec3_t mins;
|
||||
vec3_t maxs;
|
||||
vec3_t size;
|
||||
func_t touch;
|
||||
func_t use;
|
||||
func_t think;
|
||||
func_t blocked;
|
||||
float nextthink;
|
||||
int groundentity;
|
||||
float health;
|
||||
float frags;
|
||||
float weapon;
|
||||
string_t weaponmodel;
|
||||
float weaponframe;
|
||||
float currentammo;
|
||||
float ammo_shells;
|
||||
float ammo_nails;
|
||||
float ammo_rockets;
|
||||
float ammo_cells;
|
||||
float items;
|
||||
float takedamage;
|
||||
int chain;
|
||||
float deadflag;
|
||||
vec3_t view_ofs;
|
||||
float button0;
|
||||
float button1;
|
||||
float button2;
|
||||
float impulse;
|
||||
float fixangle;
|
||||
vec3_t v_angle;
|
||||
float idealpitch;
|
||||
string_t netname;
|
||||
int enemy;
|
||||
float flags;
|
||||
float colormap;
|
||||
float team;
|
||||
float max_health;
|
||||
float teleport_time;
|
||||
float armortype;
|
||||
float armorvalue;
|
||||
float waterlevel;
|
||||
float watertype;
|
||||
float ideal_yaw;
|
||||
float yaw_speed;
|
||||
int aiment;
|
||||
int goalentity;
|
||||
float spawnflags;
|
||||
string_t target;
|
||||
string_t targetname;
|
||||
float dmg_take;
|
||||
float dmg_save;
|
||||
int dmg_inflictor;
|
||||
int owner;
|
||||
vec3_t movedir;
|
||||
string_t message;
|
||||
float sounds;
|
||||
string_t noise;
|
||||
string_t noise1;
|
||||
string_t noise2;
|
||||
string_t noise3;
|
||||
} entvars_t;
|
||||
|
||||
#define PROGHEADER_CRC 5927
|
158
NQ/progdefs.q2
Normal file
158
NQ/progdefs.q2
Normal file
@ -0,0 +1,158 @@
|
||||
|
||||
/* file generated by qcc, do not modify */
|
||||
|
||||
typedef struct
|
||||
{ int pad[28];
|
||||
int self;
|
||||
int other;
|
||||
int world;
|
||||
float time;
|
||||
float frametime;
|
||||
float force_retouch;
|
||||
string_t mapname;
|
||||
string_t startspot;
|
||||
float deathmatch;
|
||||
float coop;
|
||||
float teamplay;
|
||||
float serverflags;
|
||||
float total_secrets;
|
||||
float total_monsters;
|
||||
float found_secrets;
|
||||
float killed_monsters;
|
||||
float parm1;
|
||||
float parm2;
|
||||
float parm3;
|
||||
float parm4;
|
||||
float parm5;
|
||||
float parm6;
|
||||
float parm7;
|
||||
float parm8;
|
||||
float parm9;
|
||||
float parm10;
|
||||
float parm11;
|
||||
float parm12;
|
||||
float parm13;
|
||||
float parm14;
|
||||
float parm15;
|
||||
float parm16;
|
||||
vec3_t v_forward;
|
||||
vec3_t v_up;
|
||||
vec3_t v_right;
|
||||
float trace_allsolid;
|
||||
float trace_startsolid;
|
||||
float trace_fraction;
|
||||
vec3_t trace_endpos;
|
||||
vec3_t trace_plane_normal;
|
||||
float trace_plane_dist;
|
||||
int trace_ent;
|
||||
float trace_inopen;
|
||||
float trace_inwater;
|
||||
int msg_entity;
|
||||
string_t null;
|
||||
func_t main;
|
||||
func_t StartFrame;
|
||||
func_t PlayerPreThink;
|
||||
func_t PlayerPostThink;
|
||||
func_t ClientKill;
|
||||
func_t ClientConnect;
|
||||
func_t PutClientInServer;
|
||||
func_t ClientDisconnect;
|
||||
func_t SetNewParms;
|
||||
func_t SetChangeParms;
|
||||
} globalvars_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float modelindex;
|
||||
vec3_t absmin;
|
||||
vec3_t absmax;
|
||||
float ltime;
|
||||
float movetype;
|
||||
float solid;
|
||||
vec3_t origin;
|
||||
vec3_t oldorigin;
|
||||
vec3_t velocity;
|
||||
vec3_t angles;
|
||||
vec3_t avelocity;
|
||||
vec3_t basevelocity;
|
||||
vec3_t punchangle;
|
||||
string_t classname;
|
||||
string_t model;
|
||||
float frame;
|
||||
float skin;
|
||||
float effects;
|
||||
float drawPercent;
|
||||
float gravity;
|
||||
float mass;
|
||||
float light_level;
|
||||
vec3_t mins;
|
||||
vec3_t maxs;
|
||||
vec3_t size;
|
||||
func_t touch;
|
||||
func_t use;
|
||||
func_t think;
|
||||
func_t blocked;
|
||||
float nextthink;
|
||||
int groundentity;
|
||||
float health;
|
||||
float frags;
|
||||
float weapon;
|
||||
string_t weaponmodel;
|
||||
float weaponframe;
|
||||
float currentammo;
|
||||
float ammo_shells;
|
||||
float ammo_nails;
|
||||
float ammo_rockets;
|
||||
float ammo_cells;
|
||||
float items;
|
||||
float items2;
|
||||
float takedamage;
|
||||
int chain;
|
||||
float deadflag;
|
||||
vec3_t view_ofs;
|
||||
float button0;
|
||||
float button1;
|
||||
float button2;
|
||||
float impulse;
|
||||
float fixangle;
|
||||
vec3_t v_angle;
|
||||
float idealpitch;
|
||||
float pitch_speed;
|
||||
string_t netname;
|
||||
int enemy;
|
||||
float flags;
|
||||
float colormap;
|
||||
float team;
|
||||
float max_health;
|
||||
float teleport_time;
|
||||
float armortype;
|
||||
float armorvalue;
|
||||
float waterlevel;
|
||||
float watertype;
|
||||
float ideal_yaw;
|
||||
float yaw_speed;
|
||||
int aiment;
|
||||
int goalentity;
|
||||
float spawnflags;
|
||||
string_t target;
|
||||
string_t targetname;
|
||||
float dmg_take;
|
||||
float dmg_save;
|
||||
int dmg_inflictor;
|
||||
int owner;
|
||||
vec3_t movedir;
|
||||
string_t message;
|
||||
float sounds;
|
||||
string_t noise;
|
||||
string_t noise1;
|
||||
string_t noise2;
|
||||
string_t noise3;
|
||||
float dmg;
|
||||
float dmgtime;
|
||||
float air_finished;
|
||||
float pain_finished;
|
||||
float radsuit_finished;
|
||||
float speed;
|
||||
} entvars_t;
|
||||
|
||||
#define PROGHEADER_CRC 31586
|
136
NQ/progs.h
Normal file
136
NQ/progs.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PROGS_H
|
||||
#define PROGS_H
|
||||
|
||||
#include "pr_comp.h" // defs shared with qcc
|
||||
#include "progdefs.h" // generated by program cdefs
|
||||
#include "common.h"
|
||||
|
||||
typedef union eval_s {
|
||||
string_t string;
|
||||
float _float;
|
||||
float vector[3];
|
||||
func_t function;
|
||||
int _int;
|
||||
int edict;
|
||||
} eval_t;
|
||||
|
||||
#define MAX_ENT_LEAFS 16
|
||||
typedef struct edict_s {
|
||||
qboolean free;
|
||||
link_t area; // linked to a division node or leaf
|
||||
|
||||
int num_leafs;
|
||||
short leafnums[MAX_ENT_LEAFS];
|
||||
|
||||
entity_state_t baseline;
|
||||
|
||||
float freetime; // sv.time when the object was freed
|
||||
entvars_t v; // C exported fields from progs
|
||||
// other fields from progs come immediately after
|
||||
} edict_t;
|
||||
|
||||
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
|
||||
|
||||
//============================================================================
|
||||
|
||||
extern dprograms_t *progs;
|
||||
extern dfunction_t *pr_functions;
|
||||
extern char *pr_strings;
|
||||
extern dstatement_t *pr_statements;
|
||||
extern globalvars_t *pr_global_struct;
|
||||
extern float *pr_globals; // same as pr_global_struct
|
||||
|
||||
// FIXME - this ok as global? Need to init before use...
|
||||
extern char *pr_string_temp;
|
||||
|
||||
extern int pr_edict_size; // in bytes
|
||||
|
||||
//============================================================================
|
||||
|
||||
void PR_Init(void);
|
||||
|
||||
void PR_ExecuteProgram(func_t fnum);
|
||||
void PR_LoadProgs(void);
|
||||
|
||||
void PR_Profile_f(void);
|
||||
|
||||
edict_t *ED_Alloc(void);
|
||||
void ED_Free(edict_t *ed);
|
||||
|
||||
// returns a copy of the string allocated from the server's string heap
|
||||
|
||||
void ED_Print(edict_t *ed);
|
||||
void ED_Write(FILE *f, edict_t *ed);
|
||||
char *ED_ParseEdict(char *data, edict_t *ent);
|
||||
|
||||
void ED_WriteGlobals(FILE *f);
|
||||
void ED_ParseGlobals(char *data);
|
||||
|
||||
void ED_LoadFromFile(char *data);
|
||||
|
||||
//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size))
|
||||
//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size)
|
||||
|
||||
edict_t *EDICT_NUM(int n);
|
||||
int NUM_FOR_EDICT(edict_t *e);
|
||||
|
||||
#define NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size))
|
||||
|
||||
#define EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts)
|
||||
#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e))
|
||||
|
||||
//============================================================================
|
||||
|
||||
#define G_FLOAT(o) (pr_globals[o])
|
||||
#define G_INT(o) (*(int *)&pr_globals[o])
|
||||
#define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o]))
|
||||
#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o))
|
||||
#define G_VECTOR(o) (&pr_globals[o])
|
||||
#define G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o])
|
||||
#define G_FUNCTION(o) (*(func_t *)&pr_globals[o])
|
||||
|
||||
#define E_FLOAT(e,o) (((float*)&e->v)[o])
|
||||
#define E_INT(e,o) (*(int *)&((float*)&e->v)[o])
|
||||
#define E_VECTOR(e,o) (&((float*)&e->v)[o])
|
||||
#define E_STRING(e,o) (pr_strings + *(string_t *)&((float*)&e->v)[o])
|
||||
|
||||
typedef void (*builtin_t) (void);
|
||||
extern builtin_t *pr_builtins;
|
||||
extern int pr_numbuiltins;
|
||||
|
||||
extern int pr_argc;
|
||||
|
||||
extern qboolean pr_trace;
|
||||
extern dfunction_t *pr_xfunction;
|
||||
extern int pr_xstatement;
|
||||
|
||||
extern unsigned short pr_crc;
|
||||
|
||||
void PR_RunError(char *error, ...);
|
||||
|
||||
void ED_PrintEdicts(void);
|
||||
void ED_PrintNum(int ent);
|
||||
|
||||
eval_t *GetEdictFieldValue(edict_t *ed, char *field);
|
||||
|
||||
#endif /* PROGS_H */
|
171
NQ/protocol.h
Normal file
171
NQ/protocol.h
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PROTOCOL_H
|
||||
#define PROTOCOL_H
|
||||
|
||||
// protocol.h -- communications protocols
|
||||
|
||||
#define PROTOCOL_VERSION 15
|
||||
|
||||
// if the high bit of the servercmd is set, the low bits are fast update flags:
|
||||
#define U_MOREBITS (1<<0)
|
||||
#define U_ORIGIN1 (1<<1)
|
||||
#define U_ORIGIN2 (1<<2)
|
||||
#define U_ORIGIN3 (1<<3)
|
||||
#define U_ANGLE2 (1<<4)
|
||||
#define U_NOLERP (1<<5) // don't interpolate movement
|
||||
#define U_FRAME (1<<6)
|
||||
#define U_SIGNAL (1<<7) // just differentiates from other updates
|
||||
|
||||
// svc_update can pass all of the fast update bits, plus more
|
||||
#define U_ANGLE1 (1<<8)
|
||||
#define U_ANGLE3 (1<<9)
|
||||
#define U_MODEL (1<<10)
|
||||
#define U_COLORMAP (1<<11)
|
||||
#define U_SKIN (1<<12)
|
||||
#define U_EFFECTS (1<<13)
|
||||
#define U_LONGENTITY (1<<14)
|
||||
|
||||
|
||||
#define SU_VIEWHEIGHT (1<<0)
|
||||
#define SU_IDEALPITCH (1<<1)
|
||||
#define SU_PUNCH1 (1<<2)
|
||||
#define SU_PUNCH2 (1<<3)
|
||||
#define SU_PUNCH3 (1<<4)
|
||||
#define SU_VELOCITY1 (1<<5)
|
||||
#define SU_VELOCITY2 (1<<6)
|
||||
#define SU_VELOCITY3 (1<<7)
|
||||
//define SU_AIMENT (1<<8) AVAILABLE BIT
|
||||
#define SU_ITEMS (1<<9)
|
||||
#define SU_ONGROUND (1<<10) // no data follows, the bit is it
|
||||
#define SU_INWATER (1<<11) // no data follows, the bit is it
|
||||
#define SU_WEAPONFRAME (1<<12)
|
||||
#define SU_ARMOR (1<<13)
|
||||
#define SU_WEAPON (1<<14)
|
||||
|
||||
// a sound with no channel is a local only sound
|
||||
#define SND_VOLUME (1<<0) // a byte
|
||||
#define SND_ATTENUATION (1<<1) // a byte
|
||||
#define SND_LOOPING (1<<2) // a long
|
||||
|
||||
|
||||
// defaults for clientinfo messages
|
||||
#define DEFAULT_VIEWHEIGHT 22
|
||||
|
||||
|
||||
// game types sent by serverinfo
|
||||
// these determine which intermission screen plays
|
||||
#define GAME_COOP 0
|
||||
#define GAME_DEATHMATCH 1
|
||||
|
||||
//==================
|
||||
// note that there are some defs.qc that mirror to these numbers
|
||||
// also related to svc_strings[] in cl_parse
|
||||
//==================
|
||||
|
||||
//
|
||||
// server to client
|
||||
//
|
||||
#define svc_bad 0
|
||||
#define svc_nop 1
|
||||
#define svc_disconnect 2
|
||||
#define svc_updatestat 3 // [byte] [long]
|
||||
#define svc_version 4 // [long] server version
|
||||
#define svc_setview 5 // [short] entity number
|
||||
#define svc_sound 6 // <see code>
|
||||
#define svc_time 7 // [float] server time
|
||||
#define svc_print 8 // [string] null terminated string
|
||||
#define svc_stufftext 9 // [string] stuffed into client's console buffer
|
||||
// the string should be \n terminated
|
||||
#define svc_setangle 10 // [angle3] set the view angle to this absolute value
|
||||
|
||||
#define svc_serverinfo 11 // [long] version
|
||||
// [string] signon string
|
||||
// [string]..[0]model cache
|
||||
// [string]...[0]sounds cache
|
||||
#define svc_lightstyle 12 // [byte] [string]
|
||||
#define svc_updatename 13 // [byte] [string]
|
||||
#define svc_updatefrags 14 // [byte] [short]
|
||||
#define svc_clientdata 15 // <shortbits + data>
|
||||
#define svc_stopsound 16 // <see code>
|
||||
#define svc_updatecolors 17 // [byte] [byte]
|
||||
#define svc_particle 18 // [vec3] <variable>
|
||||
#define svc_damage 19
|
||||
|
||||
#define svc_spawnstatic 20
|
||||
// svc_spawnbinary 21
|
||||
#define svc_spawnbaseline 22
|
||||
|
||||
#define svc_temp_entity 23
|
||||
|
||||
#define svc_setpause 24 // [byte] on / off
|
||||
#define svc_signonnum 25 // [byte] used for the signon sequence
|
||||
|
||||
#define svc_centerprint 26 // [string] to put in center of the screen
|
||||
|
||||
#define svc_killedmonster 27
|
||||
#define svc_foundsecret 28
|
||||
|
||||
#define svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten
|
||||
|
||||
#define svc_intermission 30 // [string] music
|
||||
#define svc_finale 31 // [string] music [string] text
|
||||
|
||||
#define svc_cdtrack 32 // [byte] track [byte] looptrack
|
||||
#define svc_sellscreen 33
|
||||
|
||||
#define svc_cutscene 34
|
||||
|
||||
//
|
||||
// client to server
|
||||
//
|
||||
#define clc_bad 0
|
||||
#define clc_nop 1
|
||||
#define clc_disconnect 2
|
||||
#define clc_move 3 // [usercmd_t]
|
||||
#define clc_stringcmd 4 // [string] message
|
||||
|
||||
|
||||
//
|
||||
// temp entity events
|
||||
//
|
||||
#define TE_SPIKE 0
|
||||
#define TE_SUPERSPIKE 1
|
||||
#define TE_GUNSHOT 2
|
||||
#define TE_EXPLOSION 3
|
||||
#define TE_TAREXPLOSION 4
|
||||
#define TE_LIGHTNING1 5
|
||||
#define TE_LIGHTNING2 6
|
||||
#define TE_WIZSPIKE 7
|
||||
#define TE_KNIGHTSPIKE 8
|
||||
#define TE_LIGHTNING3 9
|
||||
#define TE_LAVASPLASH 10
|
||||
#define TE_TELEPORT 11
|
||||
#define TE_EXPLOSION2 12
|
||||
|
||||
// PGM 01/21/97
|
||||
#define TE_BEAM 13
|
||||
// PGM 01/21/97
|
||||
|
||||
// FIXME - use this properly...
|
||||
#define MAX_CLIENTS 16
|
||||
|
||||
#endif /* PROTOCOL_H */
|
BIN
NQ/qe3.ico
Normal file
BIN
NQ/qe3.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 766 B |
BIN
NQ/quake.gif
Normal file
BIN
NQ/quake.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
NQ/quake.ico
Normal file
BIN
NQ/quake.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
233
NQ/quakedef.h
Normal file
233
NQ/quakedef.h
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// quakedef.h -- primary header for client
|
||||
// -- FIXME - needs splitting up into components...
|
||||
|
||||
#ifndef QUAKEDEF_H
|
||||
#define QUAKEDEF_H
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "cvar.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
//define PARANOID // speed sapping error checking
|
||||
|
||||
#define GAMENAME "id1" // directory to look in by default
|
||||
|
||||
#if defined(__i386__)
|
||||
#define id386 1
|
||||
#else
|
||||
#define id386 0
|
||||
#endif
|
||||
|
||||
/* UNALIGNED_OK - undef if unaligned accesses are not supported */
|
||||
#if id386
|
||||
#define UNALIGNED_OK
|
||||
#else
|
||||
#undef UNALIGNED_OK
|
||||
#endif
|
||||
|
||||
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
|
||||
#define CACHE_SIZE 32 // used to align key data structures
|
||||
|
||||
#define UNUSED(x) (x = x) // for pesky compiler / lint warnings
|
||||
|
||||
#define MINIMUM_MEMORY 0x550000
|
||||
#define MINIMUM_MEMORY_LEVELPAK (MINIMUM_MEMORY + 0x100000)
|
||||
|
||||
#define MAX_NUM_ARGVS 50
|
||||
|
||||
// up / down
|
||||
#define PITCH 0
|
||||
|
||||
// left / right
|
||||
#define YAW 1
|
||||
|
||||
// fall over
|
||||
#define ROLL 2
|
||||
|
||||
|
||||
#define MAX_QPATH 64 // max length of a quake game pathname
|
||||
#define MAX_OSPATH 128 // max length of a filesystem pathname
|
||||
|
||||
#define ON_EPSILON 0.1 // point on plane side epsilon
|
||||
|
||||
#define MAX_MSGLEN 8000 // max length of a reliable message
|
||||
#define MAX_DATAGRAM 1024 // max length of unreliable message
|
||||
|
||||
//
|
||||
// per-level limits
|
||||
//
|
||||
//#define MAX_EDICTS 600 // FIXME: ouch! ouch! ouch!
|
||||
#define MAX_EDICTS 2048 // FIXME: Arbitrary increase, make dynamic?
|
||||
#define MAX_LIGHTSTYLES 64
|
||||
#define MAX_MODELS 256 // these are sent over the net as bytes
|
||||
#define MAX_SOUNDS 256 // so they cannot be blindly increased
|
||||
|
||||
#define SAVEGAME_COMMENT_LENGTH 39
|
||||
|
||||
#define MAX_STYLESTRING 64
|
||||
|
||||
//
|
||||
// stats are integers communicated to the client by the server
|
||||
//
|
||||
#define MAX_CL_STATS 32
|
||||
#define STAT_HEALTH 0
|
||||
#define STAT_FRAGS 1
|
||||
#define STAT_WEAPON 2
|
||||
#define STAT_AMMO 3
|
||||
#define STAT_ARMOR 4
|
||||
#define STAT_WEAPONFRAME 5
|
||||
#define STAT_SHELLS 6
|
||||
#define STAT_NAILS 7
|
||||
#define STAT_ROCKETS 8
|
||||
#define STAT_CELLS 9
|
||||
#define STAT_ACTIVEWEAPON 10
|
||||
#define STAT_TOTALSECRETS 11
|
||||
#define STAT_TOTALMONSTERS 12
|
||||
#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret
|
||||
#define STAT_MONSTERS 14 // bumped by svc_killedmonster
|
||||
|
||||
// stock defines
|
||||
|
||||
#define IT_SHOTGUN 1
|
||||
#define IT_SUPER_SHOTGUN 2
|
||||
#define IT_NAILGUN 4
|
||||
#define IT_SUPER_NAILGUN 8
|
||||
#define IT_GRENADE_LAUNCHER 16
|
||||
#define IT_ROCKET_LAUNCHER 32
|
||||
#define IT_LIGHTNING 64
|
||||
#define IT_SUPER_LIGHTNING 128
|
||||
#define IT_SHELLS 256
|
||||
#define IT_NAILS 512
|
||||
#define IT_ROCKETS 1024
|
||||
#define IT_CELLS 2048
|
||||
#define IT_AXE 4096
|
||||
#define IT_ARMOR1 8192
|
||||
#define IT_ARMOR2 16384
|
||||
#define IT_ARMOR3 32768
|
||||
#define IT_SUPERHEALTH 65536
|
||||
#define IT_KEY1 131072
|
||||
#define IT_KEY2 262144
|
||||
#define IT_INVISIBILITY 524288
|
||||
#define IT_INVULNERABILITY 1048576
|
||||
#define IT_SUIT 2097152
|
||||
#define IT_QUAD 4194304
|
||||
#define IT_SIGIL1 (1<<28)
|
||||
#define IT_SIGIL2 (1<<29)
|
||||
#define IT_SIGIL3 (1<<30)
|
||||
#define IT_SIGIL4 (1<<31)
|
||||
|
||||
//===========================================
|
||||
//rogue changed and added defines
|
||||
|
||||
#define RIT_SHELLS 128
|
||||
#define RIT_NAILS 256
|
||||
#define RIT_ROCKETS 512
|
||||
#define RIT_CELLS 1024
|
||||
#define RIT_AXE 2048
|
||||
#define RIT_LAVA_NAILGUN 4096
|
||||
#define RIT_LAVA_SUPER_NAILGUN 8192
|
||||
#define RIT_MULTI_GRENADE 16384
|
||||
#define RIT_MULTI_ROCKET 32768
|
||||
#define RIT_PLASMA_GUN 65536
|
||||
#define RIT_ARMOR1 8388608
|
||||
#define RIT_ARMOR2 16777216
|
||||
#define RIT_ARMOR3 33554432
|
||||
#define RIT_LAVA_NAILS 67108864
|
||||
#define RIT_PLASMA_AMMO 134217728
|
||||
#define RIT_MULTI_ROCKETS 268435456
|
||||
#define RIT_SHIELD 536870912
|
||||
#define RIT_ANTIGRAV 1073741824
|
||||
#define RIT_SUPERHEALTH 2147483648
|
||||
|
||||
//MED 01/04/97 added hipnotic defines
|
||||
//===========================================
|
||||
//hipnotic added defines
|
||||
#define HIT_MJOLNIR_BIT 7
|
||||
#define HIT_PROXIMITY_GUN_BIT 16
|
||||
#define HIT_LASER_CANNON_BIT 23
|
||||
#define HIT_MJOLNIR (1<<HIT_MJOLNIR_BIT)
|
||||
#define HIT_PROXIMITY_GUN (1<<HIT_PROXIMITY_GUN_BIT)
|
||||
#define HIT_LASER_CANNON (1<<HIT_LASER_CANNON_BIT)
|
||||
#define HIT_WETSUIT (1<<(23+2))
|
||||
#define HIT_EMPATHY_SHIELDS (1<<(23+3))
|
||||
|
||||
//===========================================
|
||||
|
||||
#define MAX_SCOREBOARD 16
|
||||
|
||||
#define SOUND_CHANNELS 8
|
||||
|
||||
// This makes anyone on id's net privileged
|
||||
// Use for multiplayer testing only - VERY dangerous!!!
|
||||
// #define IDGODS
|
||||
|
||||
|
||||
typedef struct {
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
int modelindex;
|
||||
int frame;
|
||||
int colormap;
|
||||
int skinnum;
|
||||
int effects;
|
||||
} entity_state_t;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// the host system specifies the base of the directory tree, the
|
||||
// command line parms passed to the program, and the amount of memory
|
||||
// available for the program to use
|
||||
|
||||
typedef struct {
|
||||
char *basedir;
|
||||
char *cachedir; // for development over ISDN lines
|
||||
int argc;
|
||||
char **argv;
|
||||
void *membase;
|
||||
int memsize;
|
||||
} quakeparms_t;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
extern qboolean noclip_anglehack;
|
||||
|
||||
//
|
||||
// chase
|
||||
//
|
||||
extern cvar_t chase_active;
|
||||
|
||||
void Chase_Init(void);
|
||||
void Chase_Reset(void);
|
||||
void Chase_Update(void);
|
||||
|
||||
extern cvar_t r_lockfrustum; // FIXME - with rendering stuff please...
|
||||
extern cvar_t r_lockpvs; // FIXME - with rendering stuff please...
|
||||
extern cvar_t r_drawflat; // FIXME - with rendering stuff please...
|
||||
|
||||
#endif /* QUAKEDEF_H */
|
736
NQ/r_alias.c
Normal file
736
NQ/r_alias.c
Normal file
@ -0,0 +1,736 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_alias.c: routines for setting up to draw alias models
|
||||
|
||||
#include "console.h"
|
||||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include "sys.h"
|
||||
|
||||
/* FIXME: shouldn't be needed (is needed for patch right now, but that should
|
||||
move) */
|
||||
#include "d_local.h"
|
||||
|
||||
/* lowest light value we'll allow, to avoid the need for inner-loop light
|
||||
clamping */
|
||||
#define LIGHT_MIN 5
|
||||
|
||||
mtriangle_t *ptriangles;
|
||||
affinetridesc_t r_affinetridesc;
|
||||
|
||||
void *acolormap; // FIXME: should go away
|
||||
|
||||
trivertx_t *r_apverts;
|
||||
|
||||
// TODO: these probably will go away with optimized rasterization
|
||||
mdl_t *pmdl;
|
||||
vec3_t r_plightvec;
|
||||
int r_ambientlight;
|
||||
float r_shadelight;
|
||||
aliashdr_t *paliashdr;
|
||||
finalvert_t *pfinalverts;
|
||||
auxvert_t *pauxverts;
|
||||
static float ziscale;
|
||||
static model_t *pmodel;
|
||||
|
||||
static vec3_t alias_forward, alias_right, alias_up;
|
||||
|
||||
static maliasskindesc_t *pskindesc;
|
||||
|
||||
int r_amodels_drawn;
|
||||
int a_skinwidth;
|
||||
int r_anumverts;
|
||||
|
||||
float aliastransform[3][4];
|
||||
|
||||
typedef struct {
|
||||
int index0;
|
||||
int index1;
|
||||
} aedge_t;
|
||||
|
||||
static aedge_t aedges[12] = {
|
||||
{0, 1}, {1, 2}, {2, 3}, {3, 0},
|
||||
{4, 5}, {5, 6}, {6, 7}, {7, 4},
|
||||
{0, 5}, {1, 4}, {2, 7}, {3, 6}
|
||||
};
|
||||
|
||||
#define NUMVERTEXNORMALS 162
|
||||
|
||||
float r_avertexnormals[NUMVERTEXNORMALS][3] = {
|
||||
#include "anorms.h"
|
||||
};
|
||||
|
||||
void R_AliasTransformAndProjectFinalVerts(finalvert_t *fv,
|
||||
stvert_t *pstverts);
|
||||
void R_AliasSetUpTransform(int trivial_accept);
|
||||
void R_AliasTransformVector(vec3_t in, vec3_t out);
|
||||
void R_AliasTransformFinalVert(finalvert_t *fv, auxvert_t *av,
|
||||
trivertx_t *pverts, stvert_t *pstverts);
|
||||
void R_AliasProjectFinalVert(finalvert_t *fv, auxvert_t *av);
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasCheckBBox
|
||||
================
|
||||
*/
|
||||
qboolean
|
||||
R_AliasCheckBBox(void)
|
||||
{
|
||||
int i, flags, frame, numv;
|
||||
aliashdr_t *pahdr;
|
||||
float zi, basepts[8][3], v0, v1, frac;
|
||||
finalvert_t *pv0, *pv1, viewpts[16];
|
||||
auxvert_t *pa0, *pa1, viewaux[16];
|
||||
maliasframedesc_t *pframedesc;
|
||||
qboolean zclipped, zfullyclipped;
|
||||
unsigned anyclip, allclip;
|
||||
int minz;
|
||||
|
||||
// expand, rotate, and translate points into worldspace
|
||||
|
||||
currententity->trivial_accept = 0;
|
||||
pmodel = currententity->model;
|
||||
pahdr = Mod_Extradata(pmodel);
|
||||
pmdl = (mdl_t *)((byte *)pahdr + pahdr->model);
|
||||
|
||||
R_AliasSetUpTransform(0);
|
||||
|
||||
// construct the base bounding box for this frame
|
||||
frame = currententity->frame;
|
||||
// TODO: don't repeat this check when drawing?
|
||||
if ((frame >= pmdl->numframes) || (frame < 0)) {
|
||||
Con_DPrintf("No such frame %d %s\n", frame, pmodel->name);
|
||||
frame = 0;
|
||||
}
|
||||
|
||||
pframedesc = &pahdr->frames[frame];
|
||||
|
||||
// x worldspace coordinates
|
||||
basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] =
|
||||
(float)pframedesc->bboxmin.v[0];
|
||||
basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] =
|
||||
(float)pframedesc->bboxmax.v[0];
|
||||
|
||||
// y worldspace coordinates
|
||||
basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] =
|
||||
(float)pframedesc->bboxmin.v[1];
|
||||
basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] =
|
||||
(float)pframedesc->bboxmax.v[1];
|
||||
|
||||
// z worldspace coordinates
|
||||
basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] =
|
||||
(float)pframedesc->bboxmin.v[2];
|
||||
basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] =
|
||||
(float)pframedesc->bboxmax.v[2];
|
||||
|
||||
zclipped = false;
|
||||
zfullyclipped = true;
|
||||
|
||||
minz = 9999;
|
||||
for (i = 0; i < 8; i++) {
|
||||
R_AliasTransformVector(&basepts[i][0], &viewaux[i].fv[0]);
|
||||
|
||||
if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE) {
|
||||
// we must clip points that are closer than the near clip plane
|
||||
viewpts[i].flags = ALIAS_Z_CLIP;
|
||||
zclipped = true;
|
||||
} else {
|
||||
if (viewaux[i].fv[2] < minz)
|
||||
minz = viewaux[i].fv[2];
|
||||
viewpts[i].flags = 0;
|
||||
zfullyclipped = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (zfullyclipped) {
|
||||
return false; // everything was near-z-clipped
|
||||
}
|
||||
|
||||
numv = 8;
|
||||
|
||||
if (zclipped) {
|
||||
// organize points by edges, use edges to get new points (possible trivial
|
||||
// reject)
|
||||
for (i = 0; i < 12; i++) {
|
||||
// edge endpoints
|
||||
pv0 = &viewpts[aedges[i].index0];
|
||||
pv1 = &viewpts[aedges[i].index1];
|
||||
pa0 = &viewaux[aedges[i].index0];
|
||||
pa1 = &viewaux[aedges[i].index1];
|
||||
|
||||
// if one end is clipped and the other isn't, make a new point
|
||||
if (pv0->flags ^ pv1->flags) {
|
||||
frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) /
|
||||
(pa1->fv[2] - pa0->fv[2]);
|
||||
viewaux[numv].fv[0] = pa0->fv[0] +
|
||||
(pa1->fv[0] - pa0->fv[0]) * frac;
|
||||
viewaux[numv].fv[1] = pa0->fv[1] +
|
||||
(pa1->fv[1] - pa0->fv[1]) * frac;
|
||||
viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE;
|
||||
viewpts[numv].flags = 0;
|
||||
numv++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// project the vertices that remain after clipping
|
||||
anyclip = 0;
|
||||
allclip = ALIAS_XY_CLIP_MASK;
|
||||
|
||||
// TODO: probably should do this loop in ASM, especially if we use floats
|
||||
for (i = 0; i < numv; i++) {
|
||||
// we don't need to bother with vertices that were z-clipped
|
||||
if (viewpts[i].flags & ALIAS_Z_CLIP)
|
||||
continue;
|
||||
|
||||
zi = 1.0 / viewaux[i].fv[2];
|
||||
|
||||
// FIXME: do with chop mode in ASM, or convert to float
|
||||
v0 = (viewaux[i].fv[0] * xscale * zi) + xcenter;
|
||||
v1 = (viewaux[i].fv[1] * yscale * zi) + ycenter;
|
||||
|
||||
flags = 0;
|
||||
|
||||
if (v0 < r_refdef.fvrectx)
|
||||
flags |= ALIAS_LEFT_CLIP;
|
||||
if (v1 < r_refdef.fvrecty)
|
||||
flags |= ALIAS_TOP_CLIP;
|
||||
if (v0 > r_refdef.fvrectright)
|
||||
flags |= ALIAS_RIGHT_CLIP;
|
||||
if (v1 > r_refdef.fvrectbottom)
|
||||
flags |= ALIAS_BOTTOM_CLIP;
|
||||
|
||||
anyclip |= flags;
|
||||
allclip &= flags;
|
||||
}
|
||||
|
||||
if (allclip)
|
||||
return false; // trivial reject off one side
|
||||
|
||||
currententity->trivial_accept = !anyclip & !zclipped;
|
||||
|
||||
if (currententity->trivial_accept) {
|
||||
if (minz > (r_aliastransition + (pmdl->size * r_resfudge))) {
|
||||
currententity->trivial_accept |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasTransformVector
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasTransformVector(vec3_t in, vec3_t out)
|
||||
{
|
||||
out[0] = DotProduct(in, aliastransform[0]) + aliastransform[0][3];
|
||||
out[1] = DotProduct(in, aliastransform[1]) + aliastransform[1][3];
|
||||
out[2] = DotProduct(in, aliastransform[2]) + aliastransform[2][3];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasPreparePoints
|
||||
|
||||
General clipped case
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasPreparePoints(void)
|
||||
{
|
||||
int i;
|
||||
stvert_t *pstverts;
|
||||
finalvert_t *fv;
|
||||
auxvert_t *av;
|
||||
mtriangle_t *ptri;
|
||||
finalvert_t *pfv[3];
|
||||
|
||||
pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts);
|
||||
r_anumverts = pmdl->numverts;
|
||||
fv = pfinalverts;
|
||||
av = pauxverts;
|
||||
|
||||
for (i = 0; i < r_anumverts; i++, fv++, av++, r_apverts++, pstverts++) {
|
||||
R_AliasTransformFinalVert(fv, av, r_apverts, pstverts);
|
||||
if (av->fv[2] < ALIAS_Z_CLIP_PLANE)
|
||||
fv->flags |= ALIAS_Z_CLIP;
|
||||
else {
|
||||
R_AliasProjectFinalVert(fv, av);
|
||||
|
||||
if (fv->v[0] < r_refdef.aliasvrect.x)
|
||||
fv->flags |= ALIAS_LEFT_CLIP;
|
||||
if (fv->v[1] < r_refdef.aliasvrect.y)
|
||||
fv->flags |= ALIAS_TOP_CLIP;
|
||||
if (fv->v[0] > r_refdef.aliasvrectright)
|
||||
fv->flags |= ALIAS_RIGHT_CLIP;
|
||||
if (fv->v[1] > r_refdef.aliasvrectbottom)
|
||||
fv->flags |= ALIAS_BOTTOM_CLIP;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// clip and draw all triangles
|
||||
//
|
||||
r_affinetridesc.numtriangles = 1;
|
||||
|
||||
ptri = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
|
||||
for (i = 0; i < pmdl->numtris; i++, ptri++) {
|
||||
pfv[0] = &pfinalverts[ptri->vertindex[0]];
|
||||
pfv[1] = &pfinalverts[ptri->vertindex[1]];
|
||||
pfv[2] = &pfinalverts[ptri->vertindex[2]];
|
||||
|
||||
if (pfv[0]->flags & pfv[1]->flags & pfv[2]->
|
||||
flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP))
|
||||
continue; // completely clipped
|
||||
|
||||
if (!((pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP))) { // totally unclipped
|
||||
r_affinetridesc.pfinalverts = pfinalverts;
|
||||
r_affinetridesc.ptriangles = ptri;
|
||||
D_PolysetDraw();
|
||||
} else { // partially clipped
|
||||
R_AliasClipTriangle(ptri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasSetUpTransform
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasSetUpTransform(int trivial_accept)
|
||||
{
|
||||
int i;
|
||||
float rotationmatrix[3][4], t2matrix[3][4];
|
||||
static float tmatrix[3][4];
|
||||
static float viewmatrix[3][4];
|
||||
vec3_t angles;
|
||||
|
||||
// TODO: should really be stored with the entity instead of being reconstructed
|
||||
// TODO: should use a look-up table
|
||||
// TODO: could cache lazily, stored in the entity
|
||||
|
||||
angles[ROLL] = currententity->angles[ROLL];
|
||||
angles[PITCH] = -currententity->angles[PITCH];
|
||||
angles[YAW] = currententity->angles[YAW];
|
||||
AngleVectors(angles, alias_forward, alias_right, alias_up);
|
||||
|
||||
tmatrix[0][0] = pmdl->scale[0];
|
||||
tmatrix[1][1] = pmdl->scale[1];
|
||||
tmatrix[2][2] = pmdl->scale[2];
|
||||
|
||||
tmatrix[0][3] = pmdl->scale_origin[0];
|
||||
tmatrix[1][3] = pmdl->scale_origin[1];
|
||||
tmatrix[2][3] = pmdl->scale_origin[2];
|
||||
|
||||
// TODO: can do this with simple matrix rearrangement
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
t2matrix[i][0] = alias_forward[i];
|
||||
t2matrix[i][1] = -alias_right[i];
|
||||
t2matrix[i][2] = alias_up[i];
|
||||
}
|
||||
|
||||
t2matrix[0][3] = -modelorg[0];
|
||||
t2matrix[1][3] = -modelorg[1];
|
||||
t2matrix[2][3] = -modelorg[2];
|
||||
|
||||
// FIXME: can do more efficiently than full concatenation
|
||||
R_ConcatTransforms(t2matrix, tmatrix, rotationmatrix);
|
||||
|
||||
// TODO: should be global, set when vright, etc., set
|
||||
VectorCopy(vright, viewmatrix[0]);
|
||||
VectorCopy(vup, viewmatrix[1]);
|
||||
VectorInverse(viewmatrix[1]);
|
||||
VectorCopy(vpn, viewmatrix[2]);
|
||||
|
||||
// viewmatrix[0][3] = 0;
|
||||
// viewmatrix[1][3] = 0;
|
||||
// viewmatrix[2][3] = 0;
|
||||
|
||||
R_ConcatTransforms(viewmatrix, rotationmatrix, aliastransform);
|
||||
|
||||
// do the scaling up of x and y to screen coordinates as part of the transform
|
||||
// for the unclipped case (it would mess up clipping in the clipped case).
|
||||
// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y
|
||||
// correspondingly so the projected x and y come out right
|
||||
// FIXME: make this work for clipped case too?
|
||||
if (trivial_accept) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
aliastransform[0][i] *= aliasxscale *
|
||||
(1.0 / ((float)0x8000 * 0x10000));
|
||||
aliastransform[1][i] *= aliasyscale *
|
||||
(1.0 / ((float)0x8000 * 0x10000));
|
||||
aliastransform[2][i] *= 1.0 / ((float)0x8000 * 0x10000);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasTransformFinalVert
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasTransformFinalVert(finalvert_t *fv, auxvert_t *av,
|
||||
trivertx_t *pverts, stvert_t *pstverts)
|
||||
{
|
||||
int temp;
|
||||
float lightcos, *plightnormal;
|
||||
|
||||
av->fv[0] = DotProduct(pverts->v, aliastransform[0]) +
|
||||
aliastransform[0][3];
|
||||
av->fv[1] = DotProduct(pverts->v, aliastransform[1]) +
|
||||
aliastransform[1][3];
|
||||
av->fv[2] = DotProduct(pverts->v, aliastransform[2]) +
|
||||
aliastransform[2][3];
|
||||
|
||||
fv->v[2] = pstverts->s;
|
||||
fv->v[3] = pstverts->t;
|
||||
|
||||
fv->flags = pstverts->onseam;
|
||||
|
||||
// lighting
|
||||
plightnormal = r_avertexnormals[pverts->lightnormalindex];
|
||||
lightcos = DotProduct(plightnormal, r_plightvec);
|
||||
temp = r_ambientlight;
|
||||
|
||||
if (lightcos < 0) {
|
||||
temp += (int)(r_shadelight * lightcos);
|
||||
|
||||
// clamp; because we limited the minimum ambient and shading light, we
|
||||
// don't have to clamp low light, just bright
|
||||
if (temp < 0)
|
||||
temp = 0;
|
||||
}
|
||||
|
||||
fv->v[4] = temp;
|
||||
}
|
||||
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasTransformAndProjectFinalVerts
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasTransformAndProjectFinalVerts(finalvert_t *fv, stvert_t *pstverts)
|
||||
{
|
||||
int i, temp;
|
||||
float lightcos, *plightnormal, zi;
|
||||
trivertx_t *pverts;
|
||||
|
||||
pverts = r_apverts;
|
||||
|
||||
for (i = 0; i < r_anumverts; i++, fv++, pverts++, pstverts++) {
|
||||
// transform and project
|
||||
zi = 1.0 / (DotProduct(pverts->v, aliastransform[2]) +
|
||||
aliastransform[2][3]);
|
||||
|
||||
// x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is
|
||||
// scaled up by 1/2**31, and the scaling cancels out for x and y in the
|
||||
// projection
|
||||
fv->v[5] = zi;
|
||||
|
||||
fv->v[0] = ((DotProduct(pverts->v, aliastransform[0]) +
|
||||
aliastransform[0][3]) * zi) + aliasxcenter;
|
||||
fv->v[1] = ((DotProduct(pverts->v, aliastransform[1]) +
|
||||
aliastransform[1][3]) * zi) + aliasycenter;
|
||||
|
||||
fv->v[2] = pstverts->s;
|
||||
fv->v[3] = pstverts->t;
|
||||
fv->flags = pstverts->onseam;
|
||||
|
||||
// lighting
|
||||
plightnormal = r_avertexnormals[pverts->lightnormalindex];
|
||||
lightcos = DotProduct(plightnormal, r_plightvec);
|
||||
temp = r_ambientlight;
|
||||
|
||||
if (lightcos < 0) {
|
||||
temp += (int)(r_shadelight * lightcos);
|
||||
|
||||
// clamp; because we limited the minimum ambient and shading light, we
|
||||
// don't have to clamp low light, just bright
|
||||
if (temp < 0)
|
||||
temp = 0;
|
||||
}
|
||||
|
||||
fv->v[4] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasProjectFinalVert
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasProjectFinalVert(finalvert_t *fv, auxvert_t *av)
|
||||
{
|
||||
float zi;
|
||||
|
||||
// project points
|
||||
zi = 1.0 / av->fv[2];
|
||||
|
||||
fv->v[5] = zi * ziscale;
|
||||
|
||||
fv->v[0] = (av->fv[0] * aliasxscale * zi) + aliasxcenter;
|
||||
fv->v[1] = (av->fv[1] * aliasyscale * zi) + aliasycenter;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasPrepareUnclippedPoints
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasPrepareUnclippedPoints(void)
|
||||
{
|
||||
stvert_t *pstverts;
|
||||
finalvert_t *fv;
|
||||
|
||||
pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts);
|
||||
r_anumverts = pmdl->numverts;
|
||||
// FIXME: just use pfinalverts directly?
|
||||
fv = pfinalverts;
|
||||
|
||||
R_AliasTransformAndProjectFinalVerts(fv, pstverts);
|
||||
|
||||
if (r_affinetridesc.drawtype)
|
||||
D_PolysetDrawFinalVerts(fv, r_anumverts);
|
||||
|
||||
r_affinetridesc.pfinalverts = pfinalverts;
|
||||
r_affinetridesc.ptriangles = (mtriangle_t *)
|
||||
((byte *)paliashdr + paliashdr->triangles);
|
||||
r_affinetridesc.numtriangles = pmdl->numtris;
|
||||
|
||||
D_PolysetDraw();
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_AliasSetupSkin
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_AliasSetupSkin(void)
|
||||
{
|
||||
int skinnum;
|
||||
int i, numskins;
|
||||
maliasskingroup_t *paliasskingroup;
|
||||
float *pskinintervals, fullskininterval;
|
||||
float skintargettime, skintime;
|
||||
|
||||
skinnum = currententity->skinnum;
|
||||
if ((skinnum >= pmdl->numskins) || (skinnum < 0)) {
|
||||
Con_DPrintf("R_AliasSetupSkin: no such skin # %d\n", skinnum);
|
||||
skinnum = 0;
|
||||
}
|
||||
|
||||
pskindesc = ((maliasskindesc_t *)
|
||||
((byte *)paliashdr + paliashdr->skindesc)) + skinnum;
|
||||
a_skinwidth = pmdl->skinwidth;
|
||||
|
||||
if (pskindesc->type == ALIAS_SKIN_GROUP) {
|
||||
paliasskingroup = (maliasskingroup_t *)((byte *)paliashdr +
|
||||
pskindesc->skin);
|
||||
pskinintervals = (float *)
|
||||
((byte *)paliashdr + paliasskingroup->intervals);
|
||||
numskins = paliasskingroup->numskins;
|
||||
fullskininterval = pskinintervals[numskins - 1];
|
||||
|
||||
skintime = cl.time + currententity->syncbase;
|
||||
|
||||
// when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval
|
||||
// values are positive, so we don't have to worry about division by 0
|
||||
skintargettime = skintime -
|
||||
((int)(skintime / fullskininterval)) * fullskininterval;
|
||||
|
||||
for (i = 0; i < (numskins - 1); i++) {
|
||||
if (pskinintervals[i] > skintargettime)
|
||||
break;
|
||||
}
|
||||
|
||||
pskindesc = &paliasskingroup->skindescs[i];
|
||||
}
|
||||
|
||||
r_affinetridesc.pskindesc = pskindesc;
|
||||
r_affinetridesc.pskin = (void *)((byte *)paliashdr + pskindesc->skin);
|
||||
r_affinetridesc.skinwidth = a_skinwidth;
|
||||
r_affinetridesc.seamfixupX16 = (a_skinwidth >> 1) << 16;
|
||||
r_affinetridesc.skinheight = pmdl->skinheight;
|
||||
|
||||
// FIXME - QW Scoreboard code here?
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasSetupLighting
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasSetupLighting(alight_t *plighting)
|
||||
{
|
||||
|
||||
// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
|
||||
// to clamp off the bottom
|
||||
r_ambientlight = plighting->ambientlight;
|
||||
|
||||
if (r_ambientlight < LIGHT_MIN)
|
||||
r_ambientlight = LIGHT_MIN;
|
||||
|
||||
r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
|
||||
|
||||
if (r_ambientlight < LIGHT_MIN)
|
||||
r_ambientlight = LIGHT_MIN;
|
||||
|
||||
r_shadelight = plighting->shadelight;
|
||||
|
||||
if (r_shadelight < 0)
|
||||
r_shadelight = 0;
|
||||
|
||||
r_shadelight *= VID_GRADES;
|
||||
|
||||
// rotate the lighting vector into the model's frame of reference
|
||||
r_plightvec[0] = DotProduct(plighting->plightvec, alias_forward);
|
||||
r_plightvec[1] = -DotProduct(plighting->plightvec, alias_right);
|
||||
r_plightvec[2] = DotProduct(plighting->plightvec, alias_up);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
R_AliasSetupFrame
|
||||
|
||||
set r_apverts
|
||||
=================
|
||||
*/
|
||||
void
|
||||
R_AliasSetupFrame(void)
|
||||
{
|
||||
int frame;
|
||||
int i, numframes;
|
||||
maliasgroup_t *paliasgroup;
|
||||
float *pintervals, fullinterval, targettime, time;
|
||||
|
||||
frame = currententity->frame;
|
||||
if ((frame >= pmdl->numframes) || (frame < 0)) {
|
||||
Con_DPrintf("R_AliasSetupFrame: no such frame %d\n", frame);
|
||||
frame = 0;
|
||||
}
|
||||
|
||||
if (paliashdr->frames[frame].type == ALIAS_SINGLE) {
|
||||
r_apverts = (trivertx_t *)
|
||||
((byte *)paliashdr + paliashdr->frames[frame].frame);
|
||||
return;
|
||||
}
|
||||
|
||||
paliasgroup = (maliasgroup_t *)
|
||||
((byte *)paliashdr + paliashdr->frames[frame].frame);
|
||||
pintervals = (float *)((byte *)paliashdr + paliasgroup->intervals);
|
||||
numframes = paliasgroup->numframes;
|
||||
fullinterval = pintervals[numframes - 1];
|
||||
|
||||
time = cl.time + currententity->syncbase;
|
||||
|
||||
//
|
||||
// when loading in Mod_LoadAliasGroup, we guaranteed all interval values
|
||||
// are positive, so we don't have to worry about division by 0
|
||||
//
|
||||
targettime = time - ((int)(time / fullinterval)) * fullinterval;
|
||||
|
||||
for (i = 0; i < (numframes - 1); i++) {
|
||||
if (pintervals[i] > targettime)
|
||||
break;
|
||||
}
|
||||
|
||||
r_apverts = (trivertx_t *)
|
||||
((byte *)paliashdr + paliasgroup->frames[i].frame);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_AliasDrawModel
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_AliasDrawModel(alight_t *plighting)
|
||||
{
|
||||
finalvert_t finalverts[MAXALIASVERTS +
|
||||
((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1];
|
||||
auxvert_t auxverts[MAXALIASVERTS];
|
||||
|
||||
r_amodels_drawn++;
|
||||
|
||||
// cache align
|
||||
pfinalverts = (finalvert_t *)
|
||||
(((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
|
||||
pauxverts = &auxverts[0];
|
||||
|
||||
paliashdr = (aliashdr_t *)Mod_Extradata(currententity->model);
|
||||
pmdl = (mdl_t *)((byte *)paliashdr + paliashdr->model);
|
||||
|
||||
R_AliasSetupSkin();
|
||||
R_AliasSetUpTransform(currententity->trivial_accept);
|
||||
R_AliasSetupLighting(plighting);
|
||||
R_AliasSetupFrame();
|
||||
|
||||
if (!currententity->colormap)
|
||||
Sys_Error("%s: !currententity->colormap", __func__);
|
||||
|
||||
r_affinetridesc.drawtype = (currententity->trivial_accept == 3) &&
|
||||
r_recursiveaffinetriangles;
|
||||
|
||||
if (r_affinetridesc.drawtype) {
|
||||
D_PolysetUpdateTables(); // FIXME: precalc...
|
||||
} else {
|
||||
#if id386
|
||||
D_Aff8Patch(currententity->colormap);
|
||||
#endif
|
||||
}
|
||||
|
||||
acolormap = currententity->colormap;
|
||||
|
||||
if (currententity != &cl.viewent)
|
||||
ziscale = ((float)0x8000) * ((float)0x10000);
|
||||
else
|
||||
ziscale = ((float)0x8000) * ((float)0x10000) * 3.0;
|
||||
|
||||
if (currententity->trivial_accept)
|
||||
R_AliasPrepareUnclippedPoints();
|
||||
else
|
||||
R_AliasPreparePoints();
|
||||
}
|
617
NQ/r_bsp.c
Normal file
617
NQ/r_bsp.c
Normal file
@ -0,0 +1,617 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_bsp.c
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include "sys.h"
|
||||
#include "console.h"
|
||||
|
||||
//
|
||||
// current entity info
|
||||
//
|
||||
qboolean insubmodel;
|
||||
entity_t *currententity;
|
||||
|
||||
// modelorg is the viewpoint reletive to
|
||||
// the currently rendering entity
|
||||
vec3_t modelorg, base_modelorg;
|
||||
|
||||
vec3_t r_entorigin; // the currently rendering entity in world coordinates
|
||||
|
||||
float entity_rotation[3][3];
|
||||
|
||||
vec3_t r_worldmodelorg;
|
||||
|
||||
int r_currentbkey;
|
||||
|
||||
typedef enum { touchessolid, drawnode, nodrawnode } solidstate_t;
|
||||
|
||||
#define MAX_BMODEL_VERTS 500 // 6K
|
||||
#define MAX_BMODEL_EDGES 1000 // 12K
|
||||
|
||||
static mvertex_t *pbverts;
|
||||
static bedge_t *pbedges;
|
||||
static int numbverts, numbedges;
|
||||
|
||||
static mvertex_t *pfrontenter, *pfrontexit;
|
||||
|
||||
static qboolean makeclippededge;
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
R_EntityRotate
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_EntityRotate(vec3_t vec)
|
||||
{
|
||||
vec3_t tvec;
|
||||
|
||||
VectorCopy(vec, tvec);
|
||||
vec[0] = DotProduct(entity_rotation[0], tvec);
|
||||
vec[1] = DotProduct(entity_rotation[1], tvec);
|
||||
vec[2] = DotProduct(entity_rotation[2], tvec);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RotateBmodel
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_RotateBmodel(void)
|
||||
{
|
||||
float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
|
||||
|
||||
// TODO: should use a look-up table
|
||||
// TODO: should really be stored with the entity instead of being reconstructed
|
||||
// TODO: could cache lazily, stored in the entity
|
||||
// TODO: share work with R_SetUpAliasTransform
|
||||
|
||||
// yaw
|
||||
angle = currententity->angles[YAW];
|
||||
angle = angle * M_PI * 2 / 360;
|
||||
s = sin(angle);
|
||||
c = cos(angle);
|
||||
|
||||
temp1[0][0] = c;
|
||||
temp1[0][1] = s;
|
||||
temp1[0][2] = 0;
|
||||
temp1[1][0] = -s;
|
||||
temp1[1][1] = c;
|
||||
temp1[1][2] = 0;
|
||||
temp1[2][0] = 0;
|
||||
temp1[2][1] = 0;
|
||||
temp1[2][2] = 1;
|
||||
|
||||
|
||||
// pitch
|
||||
angle = currententity->angles[PITCH];
|
||||
angle = angle * M_PI * 2 / 360;
|
||||
s = sin(angle);
|
||||
c = cos(angle);
|
||||
|
||||
temp2[0][0] = c;
|
||||
temp2[0][1] = 0;
|
||||
temp2[0][2] = -s;
|
||||
temp2[1][0] = 0;
|
||||
temp2[1][1] = 1;
|
||||
temp2[1][2] = 0;
|
||||
temp2[2][0] = s;
|
||||
temp2[2][1] = 0;
|
||||
temp2[2][2] = c;
|
||||
|
||||
R_ConcatRotations(temp2, temp1, temp3);
|
||||
|
||||
// roll
|
||||
angle = currententity->angles[ROLL];
|
||||
angle = angle * M_PI * 2 / 360;
|
||||
s = sin(angle);
|
||||
c = cos(angle);
|
||||
|
||||
temp1[0][0] = 1;
|
||||
temp1[0][1] = 0;
|
||||
temp1[0][2] = 0;
|
||||
temp1[1][0] = 0;
|
||||
temp1[1][1] = c;
|
||||
temp1[1][2] = s;
|
||||
temp1[2][0] = 0;
|
||||
temp1[2][1] = -s;
|
||||
temp1[2][2] = c;
|
||||
|
||||
R_ConcatRotations(temp1, temp3, entity_rotation);
|
||||
|
||||
//
|
||||
// rotate modelorg and the transformation matrix
|
||||
//
|
||||
R_EntityRotate(modelorg);
|
||||
R_EntityRotate(vpn);
|
||||
R_EntityRotate(vright);
|
||||
R_EntityRotate(vup);
|
||||
|
||||
R_TransformFrustum();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RecursiveClipBPoly
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_RecursiveClipBPoly(bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
|
||||
{
|
||||
bedge_t *psideedges[2], *pnextedge, *ptedge;
|
||||
int i, side, lastside;
|
||||
float dist, frac, lastdist;
|
||||
mplane_t *splitplane, tplane;
|
||||
mvertex_t *pvert, *plastvert, *ptvert;
|
||||
mnode_t *pn;
|
||||
|
||||
psideedges[0] = psideedges[1] = NULL;
|
||||
|
||||
makeclippededge = false;
|
||||
|
||||
// transform the BSP plane into model space
|
||||
// FIXME: cache these?
|
||||
splitplane = pnode->plane;
|
||||
tplane.dist = splitplane->dist -
|
||||
DotProduct(r_entorigin, splitplane->normal);
|
||||
tplane.normal[0] = DotProduct(entity_rotation[0], splitplane->normal);
|
||||
tplane.normal[1] = DotProduct(entity_rotation[1], splitplane->normal);
|
||||
tplane.normal[2] = DotProduct(entity_rotation[2], splitplane->normal);
|
||||
|
||||
// clip edges to BSP plane
|
||||
for (; pedges; pedges = pnextedge) {
|
||||
pnextedge = pedges->pnext;
|
||||
|
||||
// set the status for the last point as the previous point
|
||||
// FIXME: cache this stuff somehow?
|
||||
plastvert = pedges->v[0];
|
||||
lastdist = DotProduct(plastvert->position, tplane.normal) -
|
||||
tplane.dist;
|
||||
|
||||
if (lastdist > 0)
|
||||
lastside = 0;
|
||||
else
|
||||
lastside = 1;
|
||||
|
||||
pvert = pedges->v[1];
|
||||
|
||||
dist = DotProduct(pvert->position, tplane.normal) - tplane.dist;
|
||||
|
||||
if (dist > 0)
|
||||
side = 0;
|
||||
else
|
||||
side = 1;
|
||||
|
||||
if (side != lastside) {
|
||||
// clipped
|
||||
if (numbverts >= MAX_BMODEL_VERTS)
|
||||
return;
|
||||
|
||||
// generate the clipped vertex
|
||||
frac = lastdist / (lastdist - dist);
|
||||
ptvert = &pbverts[numbverts++];
|
||||
ptvert->position[0] = plastvert->position[0] +
|
||||
frac * (pvert->position[0] - plastvert->position[0]);
|
||||
ptvert->position[1] = plastvert->position[1] +
|
||||
frac * (pvert->position[1] - plastvert->position[1]);
|
||||
ptvert->position[2] = plastvert->position[2] +
|
||||
frac * (pvert->position[2] - plastvert->position[2]);
|
||||
|
||||
// split into two edges, one on each side, and remember entering
|
||||
// and exiting points
|
||||
// FIXME: share the clip edge by having a winding direction flag?
|
||||
if (numbedges >= (MAX_BMODEL_EDGES - 1)) {
|
||||
Con_Printf("Out of edges for bmodel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptedge = &pbedges[numbedges];
|
||||
ptedge->pnext = psideedges[lastside];
|
||||
psideedges[lastside] = ptedge;
|
||||
ptedge->v[0] = plastvert;
|
||||
ptedge->v[1] = ptvert;
|
||||
|
||||
ptedge = &pbedges[numbedges + 1];
|
||||
ptedge->pnext = psideedges[side];
|
||||
psideedges[side] = ptedge;
|
||||
ptedge->v[0] = ptvert;
|
||||
ptedge->v[1] = pvert;
|
||||
|
||||
numbedges += 2;
|
||||
|
||||
if (side == 0) {
|
||||
// entering for front, exiting for back
|
||||
pfrontenter = ptvert;
|
||||
makeclippededge = true;
|
||||
} else {
|
||||
pfrontexit = ptvert;
|
||||
makeclippededge = true;
|
||||
}
|
||||
} else {
|
||||
// add the edge to the appropriate side
|
||||
pedges->pnext = psideedges[side];
|
||||
psideedges[side] = pedges;
|
||||
}
|
||||
}
|
||||
|
||||
// if anything was clipped, reconstitute and add the edges along the clip
|
||||
// plane to both sides (but in opposite directions)
|
||||
if (makeclippededge) {
|
||||
if (numbedges >= (MAX_BMODEL_EDGES - 2)) {
|
||||
Con_Printf("Out of edges for bmodel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptedge = &pbedges[numbedges];
|
||||
ptedge->pnext = psideedges[0];
|
||||
psideedges[0] = ptedge;
|
||||
ptedge->v[0] = pfrontexit;
|
||||
ptedge->v[1] = pfrontenter;
|
||||
|
||||
ptedge = &pbedges[numbedges + 1];
|
||||
ptedge->pnext = psideedges[1];
|
||||
psideedges[1] = ptedge;
|
||||
ptedge->v[0] = pfrontenter;
|
||||
ptedge->v[1] = pfrontexit;
|
||||
|
||||
numbedges += 2;
|
||||
}
|
||||
// draw or recurse further
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (psideedges[i]) {
|
||||
/*
|
||||
* draw if we've reached a non-solid leaf, done if all that's left
|
||||
* is a solid leaf, and continue down the tree if it's not a leaf
|
||||
*/
|
||||
pn = pnode->children[i];
|
||||
|
||||
// we're done with this branch if the node or leaf isn't in the PVS
|
||||
if (pn->visframe == r_visframecount) {
|
||||
if (pn->contents < 0) {
|
||||
if (pn->contents != CONTENTS_SOLID) {
|
||||
r_currentbkey = ((mleaf_t *)pn)->key;
|
||||
R_RenderBmodelFace(psideedges[i], psurf);
|
||||
}
|
||||
} else {
|
||||
R_RecursiveClipBPoly(psideedges[i], pnode->children[i],
|
||||
psurf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSolidClippedSubmodelPolygons
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_DrawSolidClippedSubmodelPolygons(model_t *pmodel)
|
||||
{
|
||||
int i, j, lindex;
|
||||
vec_t dot;
|
||||
msurface_t *psurf;
|
||||
int numsurfaces;
|
||||
mplane_t *pplane;
|
||||
mvertex_t bverts[MAX_BMODEL_VERTS];
|
||||
bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
|
||||
medge_t *pedge, *pedges;
|
||||
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
|
||||
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||
numsurfaces = pmodel->nummodelsurfaces;
|
||||
pedges = pmodel->edges;
|
||||
|
||||
for (i = 0; i < numsurfaces; i++, psurf++) {
|
||||
// find which side of the node we are on
|
||||
pplane = psurf->plane;
|
||||
|
||||
dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
|
||||
|
||||
// draw the polygon
|
||||
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
||||
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
|
||||
// copy the edges to bedges, flipping if necessary so always
|
||||
// clockwise winding
|
||||
|
||||
/*
|
||||
* FIXME: if edges and vertices get caches, these assignments must
|
||||
* move outside the loop, and overflow checking must be done here
|
||||
*/
|
||||
pbverts = bverts;
|
||||
pbedges = bedges;
|
||||
numbverts = numbedges = 0;
|
||||
|
||||
if (psurf->numedges > 0) {
|
||||
pbedge = &bedges[numbedges];
|
||||
numbedges += psurf->numedges;
|
||||
|
||||
for (j = 0; j < psurf->numedges; j++) {
|
||||
lindex = pmodel->surfedges[psurf->firstedge + j];
|
||||
|
||||
if (lindex > 0) {
|
||||
pedge = &pedges[lindex];
|
||||
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
|
||||
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
|
||||
} else {
|
||||
lindex = -lindex;
|
||||
pedge = &pedges[lindex];
|
||||
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
|
||||
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
|
||||
}
|
||||
|
||||
pbedge[j].pnext = &pbedge[j + 1];
|
||||
}
|
||||
|
||||
pbedge[j - 1].pnext = NULL; // mark end of edges
|
||||
|
||||
R_RecursiveClipBPoly(pbedge, currententity->topnode, psurf);
|
||||
} else {
|
||||
Sys_Error("no edges in bmodel");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSubmodelPolygons
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_DrawSubmodelPolygons(model_t *pmodel, int clipflags)
|
||||
{
|
||||
int i;
|
||||
vec_t dot;
|
||||
msurface_t *psurf;
|
||||
int numsurfaces;
|
||||
mplane_t *pplane;
|
||||
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
|
||||
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
|
||||
numsurfaces = pmodel->nummodelsurfaces;
|
||||
|
||||
for (i = 0; i < numsurfaces; i++, psurf++) {
|
||||
// find which side of the node we are on
|
||||
pplane = psurf->plane;
|
||||
|
||||
dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
|
||||
|
||||
// draw the polygon
|
||||
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
||||
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) {
|
||||
r_currentkey = ((mleaf_t *)currententity->topnode)->key;
|
||||
|
||||
// FIXME: use bounding-box-based frustum clipping info?
|
||||
R_RenderFace(psurf, clipflags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RecursiveWorldNode
|
||||
================
|
||||
*/
|
||||
static void
|
||||
R_RecursiveWorldNode(mnode_t *node, int clipflags)
|
||||
{
|
||||
int i, c, side, *pindex;
|
||||
vec3_t acceptpt, rejectpt;
|
||||
mplane_t *plane;
|
||||
msurface_t *surf, **mark;
|
||||
mleaf_t *pleaf;
|
||||
double d, dot;
|
||||
|
||||
if (node->contents == CONTENTS_SOLID)
|
||||
return; // solid
|
||||
|
||||
if (node->visframe != r_visframecount)
|
||||
return;
|
||||
|
||||
// cull the clipping planes if not trivial accept
|
||||
// FIXME: the compiler is doing a lousy job of optimizing here; it could be
|
||||
// twice as fast in ASM
|
||||
if (clipflags) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (!(clipflags & (1 << i)))
|
||||
continue; // don't need to clip against it
|
||||
|
||||
// generate accept and reject points
|
||||
// FIXME: do with fast look-ups or integer tests based on the sign
|
||||
// bit of the floating point values
|
||||
|
||||
pindex = pfrustum_indexes[i];
|
||||
|
||||
rejectpt[0] = (float)node->minmaxs[pindex[0]];
|
||||
rejectpt[1] = (float)node->minmaxs[pindex[1]];
|
||||
rejectpt[2] = (float)node->minmaxs[pindex[2]];
|
||||
|
||||
d = DotProduct(rejectpt, view_clipplanes[i].normal);
|
||||
d -= view_clipplanes[i].dist;
|
||||
|
||||
if (d <= 0)
|
||||
return;
|
||||
|
||||
acceptpt[0] = (float)node->minmaxs[pindex[3 + 0]];
|
||||
acceptpt[1] = (float)node->minmaxs[pindex[3 + 1]];
|
||||
acceptpt[2] = (float)node->minmaxs[pindex[3 + 2]];
|
||||
|
||||
d = DotProduct(acceptpt, view_clipplanes[i].normal);
|
||||
d -= view_clipplanes[i].dist;
|
||||
|
||||
if (d >= 0)
|
||||
clipflags &= ~(1 << i); // node is entirely on screen
|
||||
}
|
||||
}
|
||||
// if a leaf node, draw stuff
|
||||
if (node->contents < 0) {
|
||||
pleaf = (mleaf_t *)node;
|
||||
|
||||
mark = pleaf->firstmarksurface;
|
||||
c = pleaf->nummarksurfaces;
|
||||
|
||||
if (c) {
|
||||
do {
|
||||
(*mark)->visframe = r_framecount;
|
||||
mark++;
|
||||
} while (--c);
|
||||
}
|
||||
// deal with model fragments in this leaf
|
||||
if (pleaf->efrags) {
|
||||
R_StoreEfrags(&pleaf->efrags);
|
||||
}
|
||||
|
||||
pleaf->key = r_currentkey;
|
||||
r_currentkey++; // all bmodels in a leaf share the same key
|
||||
} else {
|
||||
// node is just a decision point, so go down the apropriate sides
|
||||
// find which side of the node we are on
|
||||
plane = node->plane;
|
||||
|
||||
switch (plane->type) {
|
||||
case PLANE_X:
|
||||
dot = modelorg[0] - plane->dist;
|
||||
break;
|
||||
case PLANE_Y:
|
||||
dot = modelorg[1] - plane->dist;
|
||||
break;
|
||||
case PLANE_Z:
|
||||
dot = modelorg[2] - plane->dist;
|
||||
break;
|
||||
default:
|
||||
dot = DotProduct(modelorg, plane->normal) - plane->dist;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dot >= 0)
|
||||
side = 0;
|
||||
else
|
||||
side = 1;
|
||||
|
||||
// recurse down the children, front side first
|
||||
R_RecursiveWorldNode(node->children[side], clipflags);
|
||||
|
||||
// draw stuff
|
||||
c = node->numsurfaces;
|
||||
|
||||
if (c) {
|
||||
surf = cl.worldmodel->surfaces + node->firstsurface;
|
||||
|
||||
if (dot < -BACKFACE_EPSILON) {
|
||||
do {
|
||||
if ((surf->flags & SURF_PLANEBACK) &&
|
||||
(surf->visframe == r_framecount)) {
|
||||
if (r_drawpolys) {
|
||||
if (r_worldpolysbacktofront) {
|
||||
if (numbtofpolys < MAX_BTOFPOLYS) {
|
||||
pbtofpolys[numbtofpolys].clipflags =
|
||||
clipflags;
|
||||
pbtofpolys[numbtofpolys].psurf = surf;
|
||||
numbtofpolys++;
|
||||
}
|
||||
} else {
|
||||
R_RenderPoly(surf, clipflags);
|
||||
}
|
||||
} else {
|
||||
R_RenderFace(surf, clipflags);
|
||||
}
|
||||
}
|
||||
|
||||
surf++;
|
||||
} while (--c);
|
||||
} else if (dot > BACKFACE_EPSILON) {
|
||||
do {
|
||||
if (!(surf->flags & SURF_PLANEBACK) &&
|
||||
(surf->visframe == r_framecount)) {
|
||||
if (r_drawpolys) {
|
||||
if (r_worldpolysbacktofront) {
|
||||
if (numbtofpolys < MAX_BTOFPOLYS) {
|
||||
pbtofpolys[numbtofpolys].clipflags =
|
||||
clipflags;
|
||||
pbtofpolys[numbtofpolys].psurf = surf;
|
||||
numbtofpolys++;
|
||||
}
|
||||
} else {
|
||||
R_RenderPoly(surf, clipflags);
|
||||
}
|
||||
} else {
|
||||
R_RenderFace(surf, clipflags);
|
||||
}
|
||||
}
|
||||
|
||||
surf++;
|
||||
} while (--c);
|
||||
}
|
||||
// all surfaces on the same node share the same sequence number
|
||||
r_currentkey++;
|
||||
}
|
||||
// recurse down the back side
|
||||
R_RecursiveWorldNode(node->children[!side], clipflags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RenderWorld
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_RenderWorld(void)
|
||||
{
|
||||
int i;
|
||||
model_t *clmodel;
|
||||
btofpoly_t btofpolys[MAX_BTOFPOLYS];
|
||||
|
||||
pbtofpolys = btofpolys;
|
||||
|
||||
currententity = &cl_entities[0];
|
||||
VectorCopy(r_origin, modelorg);
|
||||
clmodel = currententity->model;
|
||||
r_pcurrentvertbase = clmodel->vertexes;
|
||||
|
||||
R_RecursiveWorldNode(clmodel->nodes, 15);
|
||||
|
||||
// if the driver wants the polygons back to front, play the visible ones back
|
||||
// in that order
|
||||
if (r_worldpolysbacktofront) {
|
||||
for (i = numbtofpolys - 1; i >= 0; i--) {
|
||||
R_RenderPoly(btofpolys[i].psurf, btofpolys[i].clipflags);
|
||||
}
|
||||
}
|
||||
}
|
1050
NQ/r_main.c
Normal file
1050
NQ/r_main.c
Normal file
File diff suppressed because it is too large
Load Diff
507
NQ/r_misc.c
Normal file
507
NQ/r_misc.c
Normal file
@ -0,0 +1,507 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_misc.c
|
||||
|
||||
#include "console.h"
|
||||
#include "host.h"
|
||||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include "render.h"
|
||||
#include "sbar.h"
|
||||
#include "screen.h"
|
||||
#include "server.h"
|
||||
#include "sys.h"
|
||||
#include "view.h"
|
||||
|
||||
/*
|
||||
===============
|
||||
R_CheckVariables
|
||||
===============
|
||||
*/
|
||||
static void
|
||||
R_CheckVariables(void)
|
||||
{
|
||||
// FIXME - do it right (cvar callback)
|
||||
static float oldbright;
|
||||
|
||||
if (r_fullbright.value != oldbright) {
|
||||
oldbright = r_fullbright.value;
|
||||
D_FlushCaches(); // so all lighting changes
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Show
|
||||
|
||||
Debugging use
|
||||
============
|
||||
*/
|
||||
void
|
||||
Show(void)
|
||||
{
|
||||
vrect_t vr;
|
||||
|
||||
vr.x = vr.y = 0;
|
||||
vr.width = vid.width;
|
||||
vr.height = vid.height;
|
||||
vr.pnext = NULL;
|
||||
VID_Update(&vr);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
R_TimeRefresh_f
|
||||
|
||||
For program optimization
|
||||
====================
|
||||
*/
|
||||
void
|
||||
R_TimeRefresh_f(void)
|
||||
{
|
||||
int i;
|
||||
float start, stop, time;
|
||||
int startangle;
|
||||
vrect_t vr;
|
||||
|
||||
startangle = r_refdef.viewangles[1];
|
||||
|
||||
start = Sys_DoubleTime();
|
||||
for (i = 0; i < 128; i++) {
|
||||
r_refdef.viewangles[1] = i / 128.0 * 360.0;
|
||||
|
||||
VID_LockBuffer();
|
||||
|
||||
R_RenderView();
|
||||
|
||||
VID_UnlockBuffer();
|
||||
|
||||
vr.x = r_refdef.vrect.x;
|
||||
vr.y = r_refdef.vrect.y;
|
||||
vr.width = r_refdef.vrect.width;
|
||||
vr.height = r_refdef.vrect.height;
|
||||
vr.pnext = NULL;
|
||||
VID_Update(&vr);
|
||||
}
|
||||
stop = Sys_DoubleTime();
|
||||
time = stop - start;
|
||||
Con_Printf("%f seconds (%f fps)\n", time, 128 / time);
|
||||
|
||||
r_refdef.viewangles[1] = startangle;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_LineGraph
|
||||
|
||||
Only called by R_DisplayTime
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_LineGraph(int x, int y, int h)
|
||||
{
|
||||
int i;
|
||||
byte *dest;
|
||||
int s;
|
||||
|
||||
// FIXME: should be disabled on no-buffer adapters, or should be in the driver
|
||||
|
||||
x += r_refdef.vrect.x;
|
||||
y += r_refdef.vrect.y;
|
||||
|
||||
dest = vid.buffer + vid.rowbytes * y + x;
|
||||
|
||||
s = r_graphheight.value;
|
||||
|
||||
if (h > s)
|
||||
h = s;
|
||||
|
||||
for (i = 0; i < h; i++, dest -= vid.rowbytes * 2) {
|
||||
dest[0] = 0xff;
|
||||
*(dest - vid.rowbytes) = 0x30;
|
||||
}
|
||||
for (; i < s; i++, dest -= vid.rowbytes * 2) {
|
||||
dest[0] = 0x30;
|
||||
*(dest - vid.rowbytes) = 0x30;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
R_TimeGraph
|
||||
|
||||
Performance monitoring tool
|
||||
==============
|
||||
*/
|
||||
#define MAX_TIMINGS 100
|
||||
void
|
||||
R_TimeGraph(void)
|
||||
{
|
||||
static int timex;
|
||||
int a;
|
||||
float r_time2;
|
||||
static byte r_timings[MAX_TIMINGS];
|
||||
int x;
|
||||
|
||||
r_time2 = Sys_DoubleTime();
|
||||
|
||||
a = (r_time2 - r_time1) / 0.01;
|
||||
//a = fabs(mouse_y * 0.05);
|
||||
//a = (int)((r_refdef.vieworg[2] + 1024)/1)%(int)r_graphheight.value;
|
||||
//a = fabs(velocity[0])/20;
|
||||
//a = ((int)fabs(origin[0])/8)%20;
|
||||
//a = (cl.idealpitch + 30)/5;
|
||||
r_timings[timex] = a;
|
||||
a = timex;
|
||||
|
||||
if (r_refdef.vrect.width <= MAX_TIMINGS)
|
||||
x = r_refdef.vrect.width - 1;
|
||||
else
|
||||
x = r_refdef.vrect.width - (r_refdef.vrect.width - MAX_TIMINGS) / 2;
|
||||
do {
|
||||
R_LineGraph(x, r_refdef.vrect.height - 2, r_timings[a]);
|
||||
if (x == 0)
|
||||
break; // screen too small to hold entire thing
|
||||
x--;
|
||||
a--;
|
||||
if (a == -1)
|
||||
a = MAX_TIMINGS - 1;
|
||||
} while (a != timex);
|
||||
|
||||
timex = (timex + 1) % MAX_TIMINGS;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintTimes
|
||||
=============
|
||||
*/
|
||||
void
|
||||
R_PrintTimes(void)
|
||||
{
|
||||
float r_time2;
|
||||
float ms;
|
||||
|
||||
r_time2 = Sys_DoubleTime();
|
||||
|
||||
ms = 1000 * (r_time2 - r_time1);
|
||||
|
||||
Con_Printf("%5.1f ms %3i/%3i/%3i poly %3i surf\n",
|
||||
ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
|
||||
c_surf = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintDSpeeds
|
||||
=============
|
||||
*/
|
||||
void
|
||||
R_PrintDSpeeds(void)
|
||||
{
|
||||
float ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, dv_time;
|
||||
|
||||
r_time2 = Sys_DoubleTime();
|
||||
|
||||
dp_time = (dp_time2 - dp_time1) * 1000;
|
||||
rw_time = (rw_time2 - rw_time1) * 1000;
|
||||
db_time = (db_time2 - db_time1) * 1000;
|
||||
se_time = (se_time2 - se_time1) * 1000;
|
||||
de_time = (de_time2 - de_time1) * 1000;
|
||||
dv_time = (dv_time2 - dv_time1) * 1000;
|
||||
ms = (r_time2 - r_time1) * 1000;
|
||||
|
||||
Con_Printf("%3i %4.1fp %3iw %4.1fb %3is %4.1fe %4.1fv\n",
|
||||
(int)ms, dp_time, (int)rw_time, db_time, (int)se_time,
|
||||
de_time, dv_time);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
R_PrintAliasStats
|
||||
=============
|
||||
*/
|
||||
void
|
||||
R_PrintAliasStats(void)
|
||||
{
|
||||
Con_Printf("%3i polygon model drawn\n", r_amodels_drawn);
|
||||
}
|
||||
|
||||
void
|
||||
WarpPalette(void)
|
||||
{
|
||||
int i, j;
|
||||
byte newpalette[768];
|
||||
int basecolor[3];
|
||||
|
||||
basecolor[0] = 130;
|
||||
basecolor[1] = 80;
|
||||
basecolor[2] = 50;
|
||||
|
||||
// pull the colors halfway to bright brown
|
||||
for (i = 0; i < 256; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
newpalette[i * 3 + j] =
|
||||
(host_basepal[i * 3 + j] + basecolor[j]) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
VID_ShiftPalette(newpalette);
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
R_TransformFrustum
|
||||
===================
|
||||
*/
|
||||
void
|
||||
R_TransformFrustum(void)
|
||||
{
|
||||
int i;
|
||||
vec3_t v, v2;
|
||||
|
||||
if (r_lockfrustum.value)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
v[0] = screenedge[i].normal[2];
|
||||
v[1] = -screenedge[i].normal[0];
|
||||
v[2] = screenedge[i].normal[1];
|
||||
|
||||
v2[0] = v[1] * vright[0] + v[2] * vup[0] + v[0] * vpn[0];
|
||||
v2[1] = v[1] * vright[1] + v[2] * vup[1] + v[0] * vpn[1];
|
||||
v2[2] = v[1] * vright[2] + v[2] * vup[2] + v[0] * vpn[2];
|
||||
|
||||
VectorCopy(v2, view_clipplanes[i].normal);
|
||||
|
||||
view_clipplanes[i].dist = DotProduct(modelorg, v2);
|
||||
}
|
||||
}
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
================
|
||||
TransformVector
|
||||
================
|
||||
*/
|
||||
void
|
||||
TransformVector(vec3_t in, vec3_t out)
|
||||
{
|
||||
out[0] = DotProduct(in, vright);
|
||||
out[1] = DotProduct(in, vup);
|
||||
out[2] = DotProduct(in, vpn);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
================
|
||||
R_TransformPlane
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_TransformPlane(mplane_t *p, float *normal, float *dist)
|
||||
{
|
||||
float d;
|
||||
|
||||
d = DotProduct(r_origin, p->normal);
|
||||
*dist = p->dist - d;
|
||||
// TODO: when we have rotating entities, this will need to use the view matrix
|
||||
TransformVector(p->normal, normal);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_SetUpFrustumIndexes
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_SetUpFrustumIndexes(void)
|
||||
{
|
||||
int i, j, *pindex;
|
||||
|
||||
pindex = r_frustum_indexes;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
if (view_clipplanes[i].normal[j] < 0) {
|
||||
pindex[j] = j;
|
||||
pindex[j + 3] = j + 3;
|
||||
} else {
|
||||
pindex[j] = j + 3;
|
||||
pindex[j + 3] = j;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: do just once at start
|
||||
pfrustum_indexes[i] = pindex;
|
||||
pindex += 6;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_SetupFrame
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_SetupFrame(void)
|
||||
{
|
||||
int edgecount;
|
||||
vrect_t vrect;
|
||||
float w, h;
|
||||
|
||||
// don't allow cheats in multiplayer
|
||||
if (cl.maxclients > 1) {
|
||||
Cvar_Set("r_draworder", "0");
|
||||
Cvar_Set("r_fullbright", "0");
|
||||
Cvar_Set("r_ambient", "0");
|
||||
Cvar_Set("r_drawflat", "0");
|
||||
}
|
||||
|
||||
if (r_numsurfs.value) {
|
||||
if ((surface_p - surfaces) > r_maxsurfsseen)
|
||||
r_maxsurfsseen = surface_p - surfaces;
|
||||
|
||||
Con_Printf("Used %d of %d surfs; %d max\n", surface_p - surfaces,
|
||||
surf_max - surfaces, r_maxsurfsseen);
|
||||
}
|
||||
|
||||
if (r_numedges.value) {
|
||||
edgecount = edge_p - r_edges;
|
||||
|
||||
if (edgecount > r_maxedgesseen)
|
||||
r_maxedgesseen = edgecount;
|
||||
|
||||
Con_Printf("Used %d of %d edges; %d max\n", edgecount,
|
||||
r_numallocatededges, r_maxedgesseen);
|
||||
}
|
||||
|
||||
r_refdef.ambientlight = r_ambient.value;
|
||||
|
||||
if (r_refdef.ambientlight < 0)
|
||||
r_refdef.ambientlight = 0;
|
||||
|
||||
if (!sv.active)
|
||||
r_draworder.value = 0; // don't let cheaters look behind walls
|
||||
|
||||
R_CheckVariables();
|
||||
|
||||
R_AnimateLight();
|
||||
|
||||
r_framecount++;
|
||||
|
||||
numbtofpolys = 0;
|
||||
|
||||
// debugging
|
||||
#if 0
|
||||
r_refdef.vieworg[0] = 80;
|
||||
r_refdef.vieworg[1] = 64;
|
||||
r_refdef.vieworg[2] = 40;
|
||||
r_refdef.viewangles[0] = 0;
|
||||
r_refdef.viewangles[1] = 46.763641357;
|
||||
r_refdef.viewangles[2] = 0;
|
||||
#endif
|
||||
|
||||
// build the transformation matrix for the given view angles
|
||||
VectorCopy(r_refdef.vieworg, modelorg);
|
||||
VectorCopy(r_refdef.vieworg, r_origin);
|
||||
|
||||
AngleVectors(r_refdef.viewangles, vpn, vright, vup);
|
||||
|
||||
// current viewleaf
|
||||
r_oldviewleaf = r_viewleaf;
|
||||
r_viewleaf = Mod_PointInLeaf(r_origin, cl.worldmodel);
|
||||
|
||||
r_dowarpold = r_dowarp;
|
||||
r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= CONTENTS_WATER);
|
||||
|
||||
if ((r_dowarp != r_dowarpold) || r_viewchanged || lcd_x.value) {
|
||||
if (r_dowarp) {
|
||||
if ((vid.width <= vid.maxwarpwidth) &&
|
||||
(vid.height <= vid.maxwarpheight)) {
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = vid.width;
|
||||
vrect.height = vid.height;
|
||||
|
||||
R_ViewChanged(&vrect, sb_lines, vid.aspect);
|
||||
} else {
|
||||
w = vid.width;
|
||||
h = vid.height;
|
||||
|
||||
if (w > vid.maxwarpwidth) {
|
||||
h *= (float)vid.maxwarpwidth / w;
|
||||
w = vid.maxwarpwidth;
|
||||
}
|
||||
|
||||
if (h > vid.maxwarpheight) {
|
||||
h = vid.maxwarpheight;
|
||||
w *= (float)vid.maxwarpheight / h;
|
||||
}
|
||||
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = (int)w;
|
||||
vrect.height = (int)h;
|
||||
|
||||
R_ViewChanged(&vrect,
|
||||
(int)((float)sb_lines *
|
||||
(h / (float)vid.height)),
|
||||
vid.aspect * (h / w) * ((float)vid.width /
|
||||
(float)vid.height));
|
||||
}
|
||||
} else {
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = vid.width;
|
||||
vrect.height = vid.height;
|
||||
|
||||
R_ViewChanged(&vrect, sb_lines, vid.aspect);
|
||||
}
|
||||
|
||||
r_viewchanged = false;
|
||||
}
|
||||
// start off with just the four screen edge clip planes
|
||||
R_TransformFrustum();
|
||||
|
||||
// save base values
|
||||
VectorCopy(vpn, base_vpn);
|
||||
VectorCopy(vright, base_vright);
|
||||
VectorCopy(vup, base_vup);
|
||||
VectorCopy(modelorg, base_modelorg);
|
||||
|
||||
R_SetSkyFrame();
|
||||
|
||||
R_SetUpFrustumIndexes();
|
||||
|
||||
r_cache_thrash = false;
|
||||
|
||||
// clear frame counts
|
||||
c_faceclip = 0;
|
||||
r_polycount = 0;
|
||||
r_drawnpolycount = 0;
|
||||
r_amodels_drawn = 0;
|
||||
r_outofsurfaces = 0;
|
||||
r_outofedges = 0;
|
||||
|
||||
D_SetupFrame();
|
||||
}
|
742
NQ/r_part.c
Normal file
742
NQ/r_part.c
Normal file
@ -0,0 +1,742 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "console.h"
|
||||
#include "quakedef.h"
|
||||
#include "server.h"
|
||||
|
||||
#ifdef GLQUAKE
|
||||
#include "glquake.h"
|
||||
#else
|
||||
#include "r_local.h"
|
||||
#endif
|
||||
|
||||
#define MAX_PARTICLES 2048 // default max # of particles at one
|
||||
// time
|
||||
#define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's
|
||||
// on the command line
|
||||
|
||||
int ramp1[8] = { 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61 };
|
||||
int ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 };
|
||||
int ramp3[8] = { 0x6d, 0x6b, 6, 5, 4, 3 };
|
||||
|
||||
particle_t *active_particles, *free_particles;
|
||||
|
||||
particle_t *particles;
|
||||
int r_numparticles;
|
||||
|
||||
vec3_t r_pright, r_pup, r_ppn;
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_InitParticles
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_InitParticles(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = COM_CheckParm("-particles");
|
||||
|
||||
if (i) {
|
||||
r_numparticles = (int)(Q_atoi(com_argv[i + 1]));
|
||||
if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
|
||||
r_numparticles = ABSOLUTE_MIN_PARTICLES;
|
||||
} else {
|
||||
r_numparticles = MAX_PARTICLES;
|
||||
}
|
||||
|
||||
particles = (particle_t *)
|
||||
Hunk_AllocName(r_numparticles * sizeof(particle_t), "particles");
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_EntityParticles
|
||||
===============
|
||||
*/
|
||||
|
||||
#define NUMVERTEXNORMALS 162
|
||||
vec3_t avelocities[NUMVERTEXNORMALS];
|
||||
float beamlength = 16;
|
||||
vec3_t avelocity = { 23, 7, 3 };
|
||||
float partstep = 0.01;
|
||||
float timescale = 0.01;
|
||||
|
||||
void
|
||||
R_EntityParticles(entity_t *ent)
|
||||
{
|
||||
int count;
|
||||
int i;
|
||||
particle_t *p;
|
||||
float angle;
|
||||
float sr, sp, sy, cr, cp, cy;
|
||||
vec3_t forward;
|
||||
float dist;
|
||||
|
||||
dist = 64;
|
||||
count = 50;
|
||||
|
||||
if (!avelocities[0][0]) {
|
||||
for (i = 0; i < NUMVERTEXNORMALS * 3; i++)
|
||||
avelocities[0][i] = (rand() & 255) * 0.01;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < NUMVERTEXNORMALS; i++) {
|
||||
angle = cl.time * avelocities[i][0];
|
||||
sy = sin(angle);
|
||||
cy = cos(angle);
|
||||
angle = cl.time * avelocities[i][1];
|
||||
sp = sin(angle);
|
||||
cp = cos(angle);
|
||||
angle = cl.time * avelocities[i][2];
|
||||
sr = sin(angle);
|
||||
cr = cos(angle);
|
||||
|
||||
forward[0] = cp * cy;
|
||||
forward[1] = cp * sy;
|
||||
forward[2] = -sp;
|
||||
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
p->die = cl.time + 0.01;
|
||||
p->color = 0x6f;
|
||||
p->type = pt_explode;
|
||||
|
||||
p->org[0] =
|
||||
ent->origin[0] + r_avertexnormals[i][0] * dist +
|
||||
forward[0] * beamlength;
|
||||
p->org[1] =
|
||||
ent->origin[1] + r_avertexnormals[i][1] * dist +
|
||||
forward[1] * beamlength;
|
||||
p->org[2] =
|
||||
ent->origin[2] + r_avertexnormals[i][2] * dist +
|
||||
forward[2] * beamlength;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ClearParticles
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_ClearParticles(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
free_particles = &particles[0];
|
||||
active_particles = NULL;
|
||||
|
||||
for (i = 0; i < r_numparticles; i++)
|
||||
particles[i].next = &particles[i + 1];
|
||||
particles[r_numparticles - 1].next = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
R_ReadPointFile_f(void)
|
||||
{
|
||||
FILE *f;
|
||||
vec3_t org;
|
||||
int r;
|
||||
int c;
|
||||
particle_t *p;
|
||||
char name[MAX_OSPATH];
|
||||
|
||||
sprintf(name, "maps/%s.pts", sv.name);
|
||||
|
||||
COM_FOpenFile(name, &f);
|
||||
if (!f) {
|
||||
Con_Printf("couldn't open %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
Con_Printf("Reading %s...\n", name);
|
||||
c = 0;
|
||||
for (;;) {
|
||||
r = fscanf(f, "%f %f %f\n", &org[0], &org[1], &org[2]);
|
||||
if (r != 3)
|
||||
break;
|
||||
c++;
|
||||
|
||||
if (!free_particles) {
|
||||
Con_Printf("Not enough free particles\n");
|
||||
break;
|
||||
}
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
p->die = 99999;
|
||||
p->color = (-c) & 15;
|
||||
p->type = pt_static;
|
||||
VectorCopy(vec3_origin, p->vel);
|
||||
VectorCopy(org, p->org);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
Con_Printf("%i points read\n", c);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ParseParticleEffect
|
||||
|
||||
Parse an effect out of the server message
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_ParseParticleEffect(void)
|
||||
{
|
||||
vec3_t org, dir;
|
||||
int i, count, msgcount, color;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
org[i] = MSG_ReadCoord();
|
||||
for (i = 0; i < 3; i++)
|
||||
dir[i] = MSG_ReadChar() * (1.0 / 16);
|
||||
msgcount = MSG_ReadByte();
|
||||
color = MSG_ReadByte();
|
||||
|
||||
if (msgcount == 255)
|
||||
count = 1024;
|
||||
else
|
||||
count = msgcount;
|
||||
|
||||
R_RunParticleEffect(org, dir, color, count);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ParticleExplosion
|
||||
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_ParticleExplosion(vec3_t org)
|
||||
{
|
||||
int i, j;
|
||||
particle_t *p;
|
||||
|
||||
for (i = 0; i < 1024; i++) {
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
p->die = cl.time + 5;
|
||||
p->color = ramp1[0];
|
||||
p->ramp = rand() & 3;
|
||||
if (i & 1) {
|
||||
p->type = pt_explode;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p->org[j] = org[j] + ((rand() % 32) - 16);
|
||||
p->vel[j] = (rand() % 512) - 256;
|
||||
}
|
||||
} else {
|
||||
p->type = pt_explode2;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p->org[j] = org[j] + ((rand() % 32) - 16);
|
||||
p->vel[j] = (rand() % 512) - 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ParticleExplosion2
|
||||
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_ParticleExplosion2(vec3_t org, int colorStart, int colorLength)
|
||||
{
|
||||
int i, j;
|
||||
particle_t *p;
|
||||
int colorMod = 0;
|
||||
|
||||
for (i = 0; i < 512; i++) {
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
p->die = cl.time + 0.3;
|
||||
p->color = colorStart + (colorMod % colorLength);
|
||||
colorMod++;
|
||||
|
||||
p->type = pt_blob;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p->org[j] = org[j] + ((rand() % 32) - 16);
|
||||
p->vel[j] = (rand() % 512) - 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_BlobExplosion
|
||||
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_BlobExplosion(vec3_t org)
|
||||
{
|
||||
int i, j;
|
||||
particle_t *p;
|
||||
|
||||
for (i = 0; i < 1024; i++) {
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
p->die = cl.time + 1 + (rand() & 8) * 0.05;
|
||||
|
||||
if (i & 1) {
|
||||
p->type = pt_blob;
|
||||
p->color = 66 + rand() % 6;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p->org[j] = org[j] + ((rand() % 32) - 16);
|
||||
p->vel[j] = (rand() % 512) - 256;
|
||||
}
|
||||
} else {
|
||||
p->type = pt_blob2;
|
||||
p->color = 150 + rand() % 6;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p->org[j] = org[j] + ((rand() % 32) - 16);
|
||||
p->vel[j] = (rand() % 512) - 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_RunParticleEffect
|
||||
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_RunParticleEffect(vec3_t org, vec3_t dir, int color, int count)
|
||||
{
|
||||
int i, j;
|
||||
particle_t *p;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
if (count == 1024) { // rocket explosion
|
||||
p->die = cl.time + 5;
|
||||
p->color = ramp1[0];
|
||||
p->ramp = rand() & 3;
|
||||
if (i & 1) {
|
||||
p->type = pt_explode;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p->org[j] = org[j] + ((rand() % 32) - 16);
|
||||
p->vel[j] = (rand() % 512) - 256;
|
||||
}
|
||||
} else {
|
||||
p->type = pt_explode2;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p->org[j] = org[j] + ((rand() % 32) - 16);
|
||||
p->vel[j] = (rand() % 512) - 256;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p->die = cl.time + 0.1 * (rand() % 5);
|
||||
p->color = (color & ~7) + (rand() & 7);
|
||||
p->type = pt_slowgrav;
|
||||
for (j = 0; j < 3; j++) {
|
||||
p->org[j] = org[j] + ((rand() & 15) - 8);
|
||||
p->vel[j] = dir[j] * 15; // + (rand()%300)-150;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_LavaSplash
|
||||
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_LavaSplash(vec3_t org)
|
||||
{
|
||||
int i, j, k;
|
||||
particle_t *p;
|
||||
float vel;
|
||||
vec3_t dir;
|
||||
|
||||
for (i = -16; i < 16; i++)
|
||||
for (j = -16; j < 16; j++)
|
||||
for (k = 0; k < 1; k++) {
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
p->die = cl.time + 2 + (rand() & 31) * 0.02;
|
||||
p->color = 224 + (rand() & 7);
|
||||
p->type = pt_slowgrav;
|
||||
|
||||
dir[0] = j * 8 + (rand() & 7);
|
||||
dir[1] = i * 8 + (rand() & 7);
|
||||
dir[2] = 256;
|
||||
|
||||
p->org[0] = org[0] + dir[0];
|
||||
p->org[1] = org[1] + dir[1];
|
||||
p->org[2] = org[2] + (rand() & 63);
|
||||
|
||||
VectorNormalize(dir);
|
||||
vel = 50 + (rand() & 63);
|
||||
VectorScale(dir, vel, p->vel);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_TeleportSplash
|
||||
|
||||
===============
|
||||
*/
|
||||
void
|
||||
R_TeleportSplash(vec3_t org)
|
||||
{
|
||||
int i, j, k;
|
||||
particle_t *p;
|
||||
float vel;
|
||||
vec3_t dir;
|
||||
|
||||
for (i = -16; i < 16; i += 4)
|
||||
for (j = -16; j < 16; j += 4)
|
||||
for (k = -24; k < 32; k += 4) {
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
p->die = cl.time + 0.2 + (rand() & 7) * 0.02;
|
||||
p->color = 7 + (rand() & 7);
|
||||
p->type = pt_slowgrav;
|
||||
|
||||
dir[0] = j * 8;
|
||||
dir[1] = i * 8;
|
||||
dir[2] = k * 8;
|
||||
|
||||
p->org[0] = org[0] + i + (rand() & 3);
|
||||
p->org[1] = org[1] + j + (rand() & 3);
|
||||
p->org[2] = org[2] + k + (rand() & 3);
|
||||
|
||||
VectorNormalize(dir);
|
||||
vel = 50 + (rand() & 63);
|
||||
VectorScale(dir, vel, p->vel);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
R_RocketTrail(vec3_t start, vec3_t end, int type)
|
||||
{
|
||||
vec3_t vec;
|
||||
float len;
|
||||
int j;
|
||||
particle_t *p;
|
||||
int dec;
|
||||
static int tracercount;
|
||||
|
||||
VectorSubtract(end, start, vec);
|
||||
len = VectorNormalize(vec);
|
||||
if (type < 128)
|
||||
dec = 3;
|
||||
else {
|
||||
dec = 1;
|
||||
type -= 128;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
len -= dec;
|
||||
|
||||
if (!free_particles)
|
||||
return;
|
||||
p = free_particles;
|
||||
free_particles = p->next;
|
||||
p->next = active_particles;
|
||||
active_particles = p;
|
||||
|
||||
VectorCopy(vec3_origin, p->vel);
|
||||
p->die = cl.time + 2;
|
||||
|
||||
switch (type) {
|
||||
case 0: // rocket trail
|
||||
p->ramp = (rand() & 3);
|
||||
p->color = ramp3[(int)p->ramp];
|
||||
p->type = pt_fire;
|
||||
for (j = 0; j < 3; j++)
|
||||
p->org[j] = start[j] + ((rand() % 6) - 3);
|
||||
break;
|
||||
|
||||
case 1: // smoke smoke
|
||||
p->ramp = (rand() & 3) + 2;
|
||||
p->color = ramp3[(int)p->ramp];
|
||||
p->type = pt_fire;
|
||||
for (j = 0; j < 3; j++)
|
||||
p->org[j] = start[j] + ((rand() % 6) - 3);
|
||||
break;
|
||||
|
||||
case 2: // blood
|
||||
p->type = pt_grav;
|
||||
p->color = 67 + (rand() & 3);
|
||||
for (j = 0; j < 3; j++)
|
||||
p->org[j] = start[j] + ((rand() % 6) - 3);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case 5: // tracer
|
||||
p->die = cl.time + 0.5;
|
||||
p->type = pt_static;
|
||||
if (type == 3)
|
||||
p->color = 52 + ((tracercount & 4) << 1);
|
||||
else
|
||||
p->color = 230 + ((tracercount & 4) << 1);
|
||||
|
||||
tracercount++;
|
||||
|
||||
VectorCopy(start, p->org);
|
||||
if (tracercount & 1) {
|
||||
p->vel[0] = 30 * vec[1];
|
||||
p->vel[1] = 30 * -vec[0];
|
||||
} else {
|
||||
p->vel[0] = 30 * -vec[1];
|
||||
p->vel[1] = 30 * vec[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // slight blood
|
||||
p->type = pt_grav;
|
||||
p->color = 67 + (rand() & 3);
|
||||
for (j = 0; j < 3; j++)
|
||||
p->org[j] = start[j] + ((rand() % 6) - 3);
|
||||
len -= 3;
|
||||
break;
|
||||
|
||||
case 6: // voor trail
|
||||
p->color = 9 * 16 + 8 + (rand() & 3);
|
||||
p->type = pt_static;
|
||||
p->die = cl.time + 0.3;
|
||||
for (j = 0; j < 3; j++)
|
||||
p->org[j] = start[j] + ((rand() & 15) - 8);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
VectorAdd(start, vec, start);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_DrawParticles
|
||||
===============
|
||||
*/
|
||||
|
||||
void
|
||||
R_DrawParticles(void)
|
||||
{
|
||||
particle_t *p, *kill;
|
||||
float grav;
|
||||
int i;
|
||||
float time2, time3;
|
||||
float time1;
|
||||
float dvel;
|
||||
float frametime;
|
||||
|
||||
#ifdef GLQUAKE
|
||||
vec3_t up, right;
|
||||
float scale;
|
||||
|
||||
/*
|
||||
* FIXME - shouldn't need to do this, just get the caller to make sure
|
||||
* multitexture is not enabled.
|
||||
*/
|
||||
GL_DisableMultitexture();
|
||||
|
||||
GL_Bind(particletexture);
|
||||
glEnable(GL_BLEND);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
VectorScale(vup, 1.5, up);
|
||||
VectorScale(vright, 1.5, right);
|
||||
#else
|
||||
D_StartParticles();
|
||||
|
||||
VectorScale(vright, xscaleshrink, r_pright);
|
||||
VectorScale(vup, yscaleshrink, r_pup);
|
||||
VectorCopy(vpn, r_ppn);
|
||||
#endif
|
||||
frametime = cl.time - cl.oldtime;
|
||||
time3 = frametime * 15;
|
||||
time2 = frametime * 10; // 15;
|
||||
time1 = frametime * 5;
|
||||
grav = frametime * sv_gravity.value * 0.05;
|
||||
dvel = 4 * frametime;
|
||||
|
||||
for (;;) {
|
||||
kill = active_particles;
|
||||
if (kill && kill->die < cl.time) {
|
||||
active_particles = kill->next;
|
||||
kill->next = free_particles;
|
||||
free_particles = kill;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (p = active_particles; p; p = p->next) {
|
||||
for (;;) {
|
||||
kill = p->next;
|
||||
if (kill && kill->die < cl.time) {
|
||||
p->next = kill->next;
|
||||
kill->next = free_particles;
|
||||
free_particles = kill;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef GLQUAKE
|
||||
// hack a scale up to keep particles from disapearing
|
||||
scale =
|
||||
(p->org[0] - r_origin[0]) * vpn[0] + (p->org[1] -
|
||||
r_origin[1]) * vpn[1]
|
||||
+ (p->org[2] - r_origin[2]) * vpn[2];
|
||||
if (scale < 20)
|
||||
scale = 1;
|
||||
else
|
||||
scale = 1 + scale * 0.004;
|
||||
glColor3ubv((byte *)&d_8to24table[(int)p->color]);
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex3fv(p->org);
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex3f(p->org[0] + up[0] * scale, p->org[1] + up[1] * scale,
|
||||
p->org[2] + up[2] * scale);
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex3f(p->org[0] + right[0] * scale,
|
||||
p->org[1] + right[1] * scale,
|
||||
p->org[2] + right[2] * scale);
|
||||
#else
|
||||
D_DrawParticle(p);
|
||||
#endif
|
||||
p->org[0] += p->vel[0] * frametime;
|
||||
p->org[1] += p->vel[1] * frametime;
|
||||
p->org[2] += p->vel[2] * frametime;
|
||||
|
||||
switch (p->type) {
|
||||
case pt_static:
|
||||
break;
|
||||
case pt_fire:
|
||||
p->ramp += time1;
|
||||
if (p->ramp >= 6)
|
||||
p->die = -1;
|
||||
else
|
||||
p->color = ramp3[(int)p->ramp];
|
||||
p->vel[2] += grav;
|
||||
break;
|
||||
|
||||
case pt_explode:
|
||||
p->ramp += time2;
|
||||
if (p->ramp >= 8)
|
||||
p->die = -1;
|
||||
else
|
||||
p->color = ramp1[(int)p->ramp];
|
||||
for (i = 0; i < 3; i++)
|
||||
p->vel[i] += p->vel[i] * dvel;
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
|
||||
case pt_explode2:
|
||||
p->ramp += time3;
|
||||
if (p->ramp >= 8)
|
||||
p->die = -1;
|
||||
else
|
||||
p->color = ramp2[(int)p->ramp];
|
||||
for (i = 0; i < 3; i++)
|
||||
p->vel[i] -= p->vel[i] * frametime;
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
|
||||
case pt_blob:
|
||||
for (i = 0; i < 3; i++)
|
||||
p->vel[i] += p->vel[i] * dvel;
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
|
||||
case pt_blob2:
|
||||
for (i = 0; i < 2; i++)
|
||||
p->vel[i] -= p->vel[i] * dvel;
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
|
||||
case pt_grav:
|
||||
|
||||
case pt_slowgrav:
|
||||
p->vel[2] -= grav;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GLQUAKE
|
||||
glEnd();
|
||||
glDisable(GL_BLEND);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
#else
|
||||
D_EndParticles();
|
||||
#endif
|
||||
}
|
158
NQ/r_shared.h
Normal file
158
NQ/r_shared.h
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef R_SHARED_H
|
||||
#define R_SHARED_H
|
||||
|
||||
#ifndef GLQUAKE
|
||||
// r_shared.h: general refresh-related stuff shared between the refresh and the
|
||||
// driver
|
||||
|
||||
#include "d_iface.h" /* polyvert_t */
|
||||
#include "mathlib.h" /* vec3_t */
|
||||
|
||||
// FIXME: clean up and move into d_iface.h
|
||||
|
||||
#define MAXVERTS 16 // max points in a surface polygon
|
||||
#define MAXWORKINGVERTS (MAXVERTS+4) // max points in an intermediate
|
||||
// polygon (while processing)
|
||||
|
||||
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
|
||||
#define MAXHEIGHT 1024
|
||||
#define MAXWIDTH 1280
|
||||
|
||||
#define INFINITE_DISTANCE 0x10000 // distance that's always guaranteed to
|
||||
// be farther away than anything in
|
||||
// the scene
|
||||
|
||||
//===================================================================
|
||||
|
||||
extern void R_DrawLine(polyvert_t *polyvert0, polyvert_t *polyvert1);
|
||||
|
||||
extern int cachewidth;
|
||||
extern pixel_t *cacheblock;
|
||||
extern int screenwidth;
|
||||
|
||||
extern float pixelAspect;
|
||||
|
||||
extern int r_drawnpolycount;
|
||||
|
||||
extern cvar_t r_clearcolor;
|
||||
|
||||
#define TURB_TABLE_SIZE (2*TURB_CYCLE)
|
||||
extern int sintable[TURB_TABLE_SIZE];
|
||||
extern int intsintable[TURB_TABLE_SIZE];
|
||||
|
||||
extern vec3_t vup, base_vup;
|
||||
extern vec3_t vpn, base_vpn;
|
||||
extern vec3_t vright, base_vright;
|
||||
extern entity_t *currententity;
|
||||
|
||||
// FIXME - reasoning behind number choice?
|
||||
#define NUMSTACKEDGES 3000
|
||||
#define MINEDGES NUMSTACKEDGES
|
||||
#define NUMSTACKSURFACES 1500
|
||||
#define MINSURFACES NUMSTACKSURFACES
|
||||
#define MAXSPANS 3000
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct espan_s {
|
||||
int u, v, count;
|
||||
struct espan_s *pnext;
|
||||
} espan_t;
|
||||
|
||||
// FIXME: compress, make a union if that will help
|
||||
// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
|
||||
typedef struct surf_s {
|
||||
struct surf_s *next; // active surface stack in r_edge.c
|
||||
struct surf_s *prev; // used in r_edge.c for active surf stack
|
||||
struct espan_s *spans; // pointer to linked list of spans to draw
|
||||
int key; // sorting key (BSP order)
|
||||
int last_u; // set during tracing
|
||||
int spanstate; // 0 = not in span
|
||||
// 1 = in span
|
||||
// -1 = in inverted span (end before
|
||||
// start)
|
||||
int flags; // currentface flags
|
||||
void *data; // associated data like msurface_t
|
||||
entity_t *entity;
|
||||
float nearzi; // nearest 1/z on surface, for mipmapping
|
||||
qboolean insubmodel;
|
||||
float d_ziorigin, d_zistepu, d_zistepv;
|
||||
|
||||
int pad[2]; // to 64 bytes
|
||||
} surf_t;
|
||||
|
||||
extern surf_t *surfaces, *surface_p, *surf_max;
|
||||
|
||||
// surfaces are generated in back to front order by the bsp, so if a surf
|
||||
// pointer is greater than another one, it should be drawn in front
|
||||
// surfaces[1] is the background, and is used as the active surface stack.
|
||||
// surfaces[0] is a dummy, because index 0 is used to indicate no surface
|
||||
// attached to an edge_t
|
||||
|
||||
//===================================================================
|
||||
|
||||
extern vec3_t sxformaxis[4]; // s axis transformed into viewspace
|
||||
extern vec3_t txformaxis[4]; // t axis transformed into viewspac
|
||||
|
||||
extern vec3_t modelorg, base_modelorg;
|
||||
|
||||
extern float xcenter, ycenter;
|
||||
extern float xscale, yscale;
|
||||
extern float xscaleinv, yscaleinv;
|
||||
extern float xscaleshrink, yscaleshrink;
|
||||
|
||||
extern int d_lightstylevalue[256]; // 8.8 frac of base light value
|
||||
|
||||
extern void TransformVector(vec3_t in, vec3_t out);
|
||||
extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
|
||||
fixed8_t endvertu, fixed8_t endvertv);
|
||||
|
||||
extern int r_skymade;
|
||||
extern void R_MakeSky(void);
|
||||
|
||||
extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
|
||||
|
||||
// flags in finalvert_t.flags
|
||||
#define ALIAS_LEFT_CLIP 0x0001
|
||||
#define ALIAS_TOP_CLIP 0x0002
|
||||
#define ALIAS_RIGHT_CLIP 0x0004
|
||||
#define ALIAS_BOTTOM_CLIP 0x0008
|
||||
#define ALIAS_Z_CLIP 0x0010
|
||||
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
|
||||
#define ALIAS_ONSEAM 0x0020 // also defined in modelgen.h;
|
||||
// must be kept in sync
|
||||
#define ALIAS_XY_CLIP_MASK 0x000F
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct edge_s {
|
||||
fixed16_t u;
|
||||
fixed16_t u_step;
|
||||
struct edge_s *prev, *next;
|
||||
unsigned short surfs[2];
|
||||
struct edge_s *nextremove;
|
||||
float nearzi;
|
||||
medge_t *owner;
|
||||
} edge_t;
|
||||
|
||||
#endif // !GLQUAKE
|
||||
|
||||
#endif /* R_SHARED_H */
|
381
NQ/r_sprite.c
Normal file
381
NQ/r_sprite.c
Normal file
@ -0,0 +1,381 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_sprite.c
|
||||
|
||||
#include "console.h"
|
||||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include "sys.h"
|
||||
|
||||
static int clip_current;
|
||||
static vec5_t clip_verts[2][MAXWORKINGVERTS];
|
||||
static int sprite_width, sprite_height;
|
||||
|
||||
spritedesc_t r_spritedesc;
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RotateSprite
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_RotateSprite(float beamlength)
|
||||
{
|
||||
vec3_t vec;
|
||||
|
||||
if (beamlength == 0.0)
|
||||
return;
|
||||
|
||||
VectorScale(r_spritedesc.vpn, -beamlength, vec);
|
||||
VectorAdd(r_entorigin, vec, r_entorigin);
|
||||
VectorSubtract(modelorg, vec, modelorg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
R_ClipSpriteFace
|
||||
|
||||
Clips the winding at clip_verts[clip_current] and changes clip_current
|
||||
Throws out the back side
|
||||
==============
|
||||
*/
|
||||
int
|
||||
R_ClipSpriteFace(int nump, clipplane_t *pclipplane)
|
||||
{
|
||||
int i, outcount;
|
||||
float dists[MAXWORKINGVERTS + 1];
|
||||
float frac, clipdist, *pclipnormal;
|
||||
float *in, *instep, *outstep, *vert2;
|
||||
|
||||
clipdist = pclipplane->dist;
|
||||
pclipnormal = pclipplane->normal;
|
||||
|
||||
// calc dists
|
||||
if (clip_current) {
|
||||
in = clip_verts[1][0];
|
||||
outstep = clip_verts[0][0];
|
||||
clip_current = 0;
|
||||
} else {
|
||||
in = clip_verts[0][0];
|
||||
outstep = clip_verts[1][0];
|
||||
clip_current = 1;
|
||||
}
|
||||
|
||||
instep = in;
|
||||
for (i = 0; i < nump; i++, instep += sizeof(vec5_t) / sizeof(float)) {
|
||||
dists[i] = DotProduct(instep, pclipnormal) - clipdist;
|
||||
}
|
||||
|
||||
// handle wraparound case
|
||||
dists[nump] = dists[0];
|
||||
memcpy(instep, in, sizeof(vec5_t));
|
||||
|
||||
|
||||
// clip the winding
|
||||
instep = in;
|
||||
outcount = 0;
|
||||
|
||||
for (i = 0; i < nump; i++, instep += sizeof(vec5_t) / sizeof(float)) {
|
||||
if (dists[i] >= 0) {
|
||||
memcpy(outstep, instep, sizeof(vec5_t));
|
||||
outstep += sizeof(vec5_t) / sizeof(float);
|
||||
outcount++;
|
||||
}
|
||||
|
||||
if (dists[i] == 0 || dists[i + 1] == 0)
|
||||
continue;
|
||||
|
||||
if ((dists[i] > 0) == (dists[i + 1] > 0))
|
||||
continue;
|
||||
|
||||
// split it into a new vertex
|
||||
frac = dists[i] / (dists[i] - dists[i + 1]);
|
||||
|
||||
vert2 = instep + sizeof(vec5_t) / sizeof(float);
|
||||
|
||||
outstep[0] = instep[0] + frac * (vert2[0] - instep[0]);
|
||||
outstep[1] = instep[1] + frac * (vert2[1] - instep[1]);
|
||||
outstep[2] = instep[2] + frac * (vert2[2] - instep[2]);
|
||||
outstep[3] = instep[3] + frac * (vert2[3] - instep[3]);
|
||||
outstep[4] = instep[4] + frac * (vert2[4] - instep[4]);
|
||||
|
||||
outstep += sizeof(vec5_t) / sizeof(float);
|
||||
outcount++;
|
||||
}
|
||||
|
||||
return outcount;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_SetupAndDrawSprite
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_SetupAndDrawSprite()
|
||||
{
|
||||
int i, nump;
|
||||
float dot, scale, *pv;
|
||||
vec5_t *pverts;
|
||||
vec3_t left, up, right, down, transformed, local;
|
||||
emitpoint_t outverts[MAXWORKINGVERTS + 1], *pout;
|
||||
|
||||
dot = DotProduct(r_spritedesc.vpn, modelorg);
|
||||
|
||||
// backface cull
|
||||
if (dot >= 0)
|
||||
return;
|
||||
|
||||
// build the sprite poster in worldspace
|
||||
VectorScale(r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
|
||||
VectorScale(r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
|
||||
VectorScale(r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
|
||||
VectorScale(r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
|
||||
|
||||
pverts = clip_verts[0];
|
||||
|
||||
pverts[0][0] = r_entorigin[0] + up[0] + left[0];
|
||||
pverts[0][1] = r_entorigin[1] + up[1] + left[1];
|
||||
pverts[0][2] = r_entorigin[2] + up[2] + left[2];
|
||||
pverts[0][3] = 0;
|
||||
pverts[0][4] = 0;
|
||||
|
||||
pverts[1][0] = r_entorigin[0] + up[0] + right[0];
|
||||
pverts[1][1] = r_entorigin[1] + up[1] + right[1];
|
||||
pverts[1][2] = r_entorigin[2] + up[2] + right[2];
|
||||
pverts[1][3] = sprite_width;
|
||||
pverts[1][4] = 0;
|
||||
|
||||
pverts[2][0] = r_entorigin[0] + down[0] + right[0];
|
||||
pverts[2][1] = r_entorigin[1] + down[1] + right[1];
|
||||
pverts[2][2] = r_entorigin[2] + down[2] + right[2];
|
||||
pverts[2][3] = sprite_width;
|
||||
pverts[2][4] = sprite_height;
|
||||
|
||||
pverts[3][0] = r_entorigin[0] + down[0] + left[0];
|
||||
pverts[3][1] = r_entorigin[1] + down[1] + left[1];
|
||||
pverts[3][2] = r_entorigin[2] + down[2] + left[2];
|
||||
pverts[3][3] = 0;
|
||||
pverts[3][4] = sprite_height;
|
||||
|
||||
// clip to the frustum in worldspace
|
||||
nump = 4;
|
||||
clip_current = 0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
nump = R_ClipSpriteFace(nump, &view_clipplanes[i]);
|
||||
if (nump < 3)
|
||||
return;
|
||||
if (nump >= MAXWORKINGVERTS)
|
||||
Sys_Error("%s: too many points", __func__);
|
||||
}
|
||||
|
||||
// transform vertices into viewspace and project
|
||||
pv = &clip_verts[clip_current][0][0];
|
||||
r_spritedesc.nearzi = -999999;
|
||||
|
||||
for (i = 0; i < nump; i++) {
|
||||
VectorSubtract(pv, r_origin, local);
|
||||
TransformVector(local, transformed);
|
||||
|
||||
if (transformed[2] < NEAR_CLIP)
|
||||
transformed[2] = NEAR_CLIP;
|
||||
|
||||
pout = &outverts[i];
|
||||
pout->zi = 1.0 / transformed[2];
|
||||
if (pout->zi > r_spritedesc.nearzi)
|
||||
r_spritedesc.nearzi = pout->zi;
|
||||
|
||||
pout->s = pv[3];
|
||||
pout->t = pv[4];
|
||||
|
||||
scale = xscale * pout->zi;
|
||||
pout->u = (xcenter + scale * transformed[0]);
|
||||
|
||||
scale = yscale * pout->zi;
|
||||
pout->v = (ycenter - scale * transformed[1]);
|
||||
|
||||
pv += sizeof(vec5_t) / sizeof(*pv);
|
||||
}
|
||||
|
||||
// draw it
|
||||
r_spritedesc.nump = nump;
|
||||
r_spritedesc.pverts = outverts;
|
||||
D_DrawSprite();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_GetSpriteframe
|
||||
================
|
||||
*/
|
||||
mspriteframe_t *
|
||||
R_GetSpriteframe(msprite_t *psprite)
|
||||
{
|
||||
mspritegroup_t *pspritegroup;
|
||||
mspriteframe_t *pspriteframe;
|
||||
int i, numframes, frame;
|
||||
float *pintervals, fullinterval, targettime, time;
|
||||
|
||||
frame = currententity->frame;
|
||||
|
||||
if ((frame >= psprite->numframes) || (frame < 0)) {
|
||||
Con_Printf("R_DrawSprite: no such frame %d\n", frame);
|
||||
frame = 0;
|
||||
}
|
||||
|
||||
if (psprite->frames[frame].type == SPR_SINGLE) {
|
||||
pspriteframe = psprite->frames[frame].frameptr;
|
||||
} else {
|
||||
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
|
||||
pintervals = pspritegroup->intervals;
|
||||
numframes = pspritegroup->numframes;
|
||||
fullinterval = pintervals[numframes - 1];
|
||||
|
||||
time = cl.time + currententity->syncbase;
|
||||
|
||||
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
|
||||
// are positive, so we don't have to worry about division by 0
|
||||
targettime = time - ((int)(time / fullinterval)) * fullinterval;
|
||||
|
||||
for (i = 0; i < (numframes - 1); i++) {
|
||||
if (pintervals[i] > targettime)
|
||||
break;
|
||||
}
|
||||
|
||||
pspriteframe = pspritegroup->frames[i];
|
||||
}
|
||||
|
||||
return pspriteframe;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSprite
|
||||
================
|
||||
*/
|
||||
void
|
||||
R_DrawSprite(void)
|
||||
{
|
||||
int i;
|
||||
msprite_t *psprite;
|
||||
vec3_t tvec;
|
||||
float dot, angle, sr, cr;
|
||||
|
||||
psprite = currententity->model->cache.data;
|
||||
|
||||
r_spritedesc.pspriteframe = R_GetSpriteframe(psprite);
|
||||
|
||||
sprite_width = r_spritedesc.pspriteframe->width;
|
||||
sprite_height = r_spritedesc.pspriteframe->height;
|
||||
|
||||
// TODO: make this caller-selectable
|
||||
if (psprite->type == SPR_FACING_UPRIGHT) {
|
||||
// generate the sprite's axes, with vup straight up in worldspace, and
|
||||
// r_spritedesc.vright perpendicular to modelorg.
|
||||
// This will not work if the view direction is very close to straight up or
|
||||
// down, because the cross product will be between two nearly parallel
|
||||
// vectors and starts to approach an undefined state, so we don't draw if
|
||||
// the two vectors are less than 1 degree apart
|
||||
tvec[0] = -modelorg[0];
|
||||
tvec[1] = -modelorg[1];
|
||||
tvec[2] = -modelorg[2];
|
||||
VectorNormalize(tvec);
|
||||
dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
|
||||
// r_spritedesc.vup is 0, 0, 1
|
||||
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
||||
return;
|
||||
r_spritedesc.vup[0] = 0;
|
||||
r_spritedesc.vup[1] = 0;
|
||||
r_spritedesc.vup[2] = 1;
|
||||
r_spritedesc.vright[0] = tvec[1];
|
||||
// CrossProduct(r_spritedesc.vup, -modelorg,
|
||||
r_spritedesc.vright[1] = -tvec[0];
|
||||
// r_spritedesc.vright)
|
||||
r_spritedesc.vright[2] = 0;
|
||||
VectorNormalize(r_spritedesc.vright);
|
||||
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
||||
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
||||
r_spritedesc.vpn[2] = 0;
|
||||
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
||||
// r_spritedesc.vpn)
|
||||
} else if (psprite->type == SPR_VP_PARALLEL) {
|
||||
// generate the sprite's axes, completely parallel to the viewplane. There
|
||||
// are no problem situations, because the sprite is always in the same
|
||||
// position relative to the viewer
|
||||
for (i = 0; i < 3; i++) {
|
||||
r_spritedesc.vup[i] = vup[i];
|
||||
r_spritedesc.vright[i] = vright[i];
|
||||
r_spritedesc.vpn[i] = vpn[i];
|
||||
}
|
||||
} else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) {
|
||||
// generate the sprite's axes, with vup straight up in worldspace, and
|
||||
// r_spritedesc.vright parallel to the viewplane.
|
||||
// This will not work if the view direction is very close to straight up or
|
||||
// down, because the cross product will be between two nearly parallel
|
||||
// vectors and starts to approach an undefined state, so we don't draw if
|
||||
// the two vectors are less than 1 degree apart
|
||||
dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
|
||||
// r_spritedesc.vup is 0, 0, 1
|
||||
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
|
||||
return;
|
||||
r_spritedesc.vup[0] = 0;
|
||||
r_spritedesc.vup[1] = 0;
|
||||
r_spritedesc.vup[2] = 1;
|
||||
r_spritedesc.vright[0] = vpn[1];
|
||||
// CrossProduct (r_spritedesc.vup, vpn,
|
||||
r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright)
|
||||
r_spritedesc.vright[2] = 0;
|
||||
VectorNormalize(r_spritedesc.vright);
|
||||
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
|
||||
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
|
||||
r_spritedesc.vpn[2] = 0;
|
||||
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
|
||||
// r_spritedesc.vpn)
|
||||
} else if (psprite->type == SPR_ORIENTED) {
|
||||
// generate the sprite's axes, according to the sprite's world orientation
|
||||
AngleVectors(currententity->angles, r_spritedesc.vpn,
|
||||
r_spritedesc.vright, r_spritedesc.vup);
|
||||
} else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) {
|
||||
// generate the sprite's axes, parallel to the viewplane, but rotated in
|
||||
// that plane around the center according to the sprite entity's roll
|
||||
// angle. So vpn stays the same, but vright and vup rotate
|
||||
angle = currententity->angles[ROLL] * (M_PI * 2 / 360);
|
||||
sr = sin(angle);
|
||||
cr = cos(angle);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
r_spritedesc.vpn[i] = vpn[i];
|
||||
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
|
||||
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
|
||||
}
|
||||
} else {
|
||||
Sys_Error("%s: Bad sprite type %d", __func__, psprite->type);
|
||||
}
|
||||
|
||||
R_RotateSprite(psprite->beamlength);
|
||||
|
||||
R_SetupAndDrawSprite();
|
||||
}
|
159
NQ/render.h
Normal file
159
NQ/render.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RENDER_H
|
||||
#define RENDER_H
|
||||
|
||||
#include "mathlib.h"
|
||||
#include "vid.h"
|
||||
|
||||
// render.h -- public interface to refresh functions
|
||||
|
||||
#define TOP_RANGE 16 // soldier uniform colors
|
||||
#define BOTTOM_RANGE 96
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef struct efrag_s {
|
||||
struct mleaf_s *leaf;
|
||||
struct efrag_s *leafnext;
|
||||
struct entity_s *entity;
|
||||
struct efrag_s *entnext;
|
||||
} efrag_t;
|
||||
|
||||
|
||||
typedef struct entity_s {
|
||||
qboolean forcelink; // model changed
|
||||
|
||||
int update_type;
|
||||
|
||||
entity_state_t baseline; // to fill in defaults in updates
|
||||
|
||||
double msgtime; // time of last update
|
||||
vec3_t msg_origins[2]; // last two updates (0 is newest)
|
||||
vec3_t msg_angles[2]; // last two updates (0 is newest)
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
struct model_s *model; // NULL = no model
|
||||
int frame;
|
||||
byte *colormap;
|
||||
int skinnum; // for Alias models
|
||||
|
||||
float syncbase; // for client-side animations
|
||||
|
||||
struct efrag_s *efrag; // linked list of efrags (FIXME)
|
||||
int visframe; // last frame this entity was
|
||||
// found in an active leaf
|
||||
|
||||
int effects; // light, particals, etc
|
||||
int dlightframe; // dynamic lighting
|
||||
int dlightbits;
|
||||
|
||||
// FIXME: could turn these into a union
|
||||
int trivial_accept;
|
||||
struct mnode_s *topnode; // for bmodels, first world node
|
||||
// that splits bmodel, or NULL if
|
||||
// not split
|
||||
} entity_t;
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_draw.h too !!!
|
||||
typedef struct {
|
||||
vrect_t vrect; // subwindow in video for refresh
|
||||
// FIXME: not need vrect next field here?
|
||||
vrect_t aliasvrect; // scaled Alias version
|
||||
int vrectright, vrectbottom; // right & bottom screen coords
|
||||
int aliasvrectright, aliasvrectbottom; // scaled Alias versions
|
||||
float vrectrightedge; // rightmost right edge we care about,
|
||||
// for use in edge list
|
||||
float fvrectx, fvrecty; // for floating-point compares
|
||||
float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping
|
||||
int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20
|
||||
int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20
|
||||
float fvrectright_adj, fvrectbottom_adj;
|
||||
// right and bottom edges, for clamping
|
||||
float fvrectright; // rightmost edge, for Alias clamping
|
||||
float fvrectbottom; // bottommost edge, for Alias clamping
|
||||
float horizontalFieldOfView; // at Z = 1.0, this many X is visible
|
||||
// 2.0 = 90 degrees
|
||||
float xOrigin; // should probably allways be 0.5
|
||||
float yOrigin; // between be around 0.3 to 0.5
|
||||
|
||||
vec3_t vieworg;
|
||||
vec3_t viewangles;
|
||||
|
||||
float fov_x, fov_y;
|
||||
|
||||
int ambientlight;
|
||||
} refdef_t;
|
||||
|
||||
|
||||
//
|
||||
// refresh
|
||||
//
|
||||
|
||||
extern refdef_t r_refdef;
|
||||
extern vec3_t r_origin, vpn, vright, vup;
|
||||
|
||||
extern struct texture_s *r_notexture_mip;
|
||||
|
||||
|
||||
void R_Init(void);
|
||||
void R_InitTextures(void);
|
||||
void R_InitEfrags(void);
|
||||
void R_RenderView(void); // must set r_refdef first
|
||||
void R_ViewChanged(vrect_t *pvrect, int lineadj, float aspect);
|
||||
|
||||
// called whenever r_refdef or vid change
|
||||
void R_InitSky(struct texture_s *mt); // called at level load
|
||||
|
||||
void R_AddEfrags(entity_t *ent);
|
||||
void R_RemoveEfrags(entity_t *ent);
|
||||
|
||||
void R_NewMap(void);
|
||||
|
||||
void R_ParseParticleEffect(void);
|
||||
void R_RunParticleEffect(vec3_t org, vec3_t dir, int color, int count);
|
||||
void R_RocketTrail(vec3_t start, vec3_t end, int type);
|
||||
|
||||
void R_EntityParticles(entity_t *ent);
|
||||
void R_BlobExplosion(vec3_t org);
|
||||
void R_ParticleExplosion(vec3_t org);
|
||||
void R_ParticleExplosion2(vec3_t org, int colorStart, int colorLength);
|
||||
void R_LavaSplash(vec3_t org);
|
||||
void R_TeleportSplash(vec3_t org);
|
||||
|
||||
void R_PushDlights(void);
|
||||
|
||||
void R_InitParticles(void);
|
||||
void R_ClearParticles(void);
|
||||
void R_DrawParticles(void);
|
||||
|
||||
//
|
||||
// surface cache related
|
||||
//
|
||||
extern qboolean r_cache_thrash; // set if thrashing the surface cache
|
||||
|
||||
int D_SurfaceCacheForRes(int width, int height);
|
||||
void D_FlushCaches(void);
|
||||
void D_DeleteSurfaceCache(void);
|
||||
void D_InitCaches(void *buffer, int size);
|
||||
void R_SetVrect(vrect_t *pvrect, vrect_t *pvrectin, int lineadj);
|
||||
|
||||
#endif /* RENDER_H */
|
20
NQ/resource.h
Normal file
20
NQ/resource.h
Normal file
@ -0,0 +1,20 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by winquake.rc
|
||||
//
|
||||
#define IDS_STRING1 1
|
||||
#define IDI_ICON2 1
|
||||
#define IDD_DIALOG1 108
|
||||
#define IDD_PROGRESS 109
|
||||
#define IDC_PROGRESS 1000
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 111
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1004
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
974
NQ/screen.c
Normal file
974
NQ/screen.c
Normal file
@ -0,0 +1,974 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// screen.c -- master for refresh, status bar, console, chat, notify, etc
|
||||
|
||||
#include "screen.h"
|
||||
#include "quakedef.h"
|
||||
#include "r_local.h"
|
||||
#include "host.h"
|
||||
#include "wad.h"
|
||||
#include "draw.h"
|
||||
#include "keys.h"
|
||||
#include "sys.h"
|
||||
#include "sbar.h"
|
||||
#include "cmd.h"
|
||||
#include "console.h"
|
||||
#include "sound.h"
|
||||
#include "view.h" /* lcd_x */
|
||||
#include "menu.h"
|
||||
|
||||
// only the refresh window will be updated unless these variables are flagged
|
||||
int scr_copytop;
|
||||
int scr_copyeverything;
|
||||
|
||||
float scr_con_current;
|
||||
float scr_conlines; // lines of console to display
|
||||
|
||||
float oldscreensize, oldfov;
|
||||
cvar_t scr_viewsize = { "viewsize", "100", true };
|
||||
cvar_t scr_fov = { "fov", "90" }; // 10 - 170
|
||||
cvar_t scr_conspeed = { "scr_conspeed", "300" };
|
||||
cvar_t scr_centertime = { "scr_centertime", "2" };
|
||||
cvar_t scr_showram = { "showram", "1" };
|
||||
cvar_t scr_showturtle = { "showturtle", "0" };
|
||||
cvar_t scr_showpause = { "showpause", "1" };
|
||||
cvar_t scr_printspeed = { "scr_printspeed", "8" };
|
||||
|
||||
qboolean scr_initialized; // ready to draw
|
||||
|
||||
qpic_t *scr_ram;
|
||||
qpic_t *scr_net;
|
||||
qpic_t *scr_turtle;
|
||||
|
||||
int scr_fullupdate;
|
||||
|
||||
int clearconsole;
|
||||
int clearnotify;
|
||||
|
||||
viddef_t vid; // global video state
|
||||
|
||||
vrect_t *pconupdate;
|
||||
vrect_t scr_vrect;
|
||||
|
||||
qboolean scr_disabled_for_loading;
|
||||
qboolean scr_drawloading;
|
||||
float scr_disabled_time;
|
||||
qboolean scr_skipupdate;
|
||||
|
||||
qboolean block_drawing;
|
||||
|
||||
void SCR_ScreenShot_f(void);
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
CENTER PRINTING
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
char scr_centerstring[1024];
|
||||
float scr_centertime_start; // for slow victory printing
|
||||
float scr_centertime_off;
|
||||
int scr_center_lines;
|
||||
int scr_erase_lines;
|
||||
int scr_erase_center;
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_CenterPrint
|
||||
|
||||
Called for important messages that should stay in the center of the screen
|
||||
for a few moments
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_CenterPrint(char *str)
|
||||
{
|
||||
strncpy(scr_centerstring, str, sizeof(scr_centerstring) - 1);
|
||||
scr_centertime_off = scr_centertime.value;
|
||||
scr_centertime_start = cl.time;
|
||||
|
||||
// count the number of lines for centering
|
||||
scr_center_lines = 1;
|
||||
while (*str) {
|
||||
if (*str == '\n')
|
||||
scr_center_lines++;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SCR_EraseCenterString(void)
|
||||
{
|
||||
int y;
|
||||
|
||||
if (scr_erase_center++ > vid.numpages) {
|
||||
scr_erase_lines = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (scr_center_lines <= 4)
|
||||
y = vid.height * 0.35;
|
||||
else
|
||||
y = 48;
|
||||
|
||||
scr_copytop = 1;
|
||||
Draw_TileClear(0, y, vid.width, 8 * scr_erase_lines);
|
||||
}
|
||||
|
||||
void
|
||||
SCR_DrawCenterString(void)
|
||||
{
|
||||
char *start;
|
||||
int l;
|
||||
int j;
|
||||
int x, y;
|
||||
int remaining;
|
||||
|
||||
// the finale prints the characters one at a time
|
||||
if (cl.intermission)
|
||||
remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
|
||||
else
|
||||
remaining = 9999;
|
||||
|
||||
scr_erase_center = 0;
|
||||
start = scr_centerstring;
|
||||
|
||||
if (scr_center_lines <= 4)
|
||||
y = vid.height * 0.35;
|
||||
else
|
||||
y = 48;
|
||||
|
||||
do {
|
||||
// scan the width of the line
|
||||
for (l = 0; l < 40; l++)
|
||||
if (start[l] == '\n' || !start[l])
|
||||
break;
|
||||
x = (vid.width - l * 8) / 2;
|
||||
for (j = 0; j < l; j++, x += 8) {
|
||||
Draw_Character(x, y, start[j]);
|
||||
if (!remaining--)
|
||||
return;
|
||||
}
|
||||
|
||||
y += 8;
|
||||
|
||||
while (*start && *start != '\n')
|
||||
start++;
|
||||
|
||||
if (!*start)
|
||||
break;
|
||||
start++; // skip the \n
|
||||
} while (1);
|
||||
}
|
||||
|
||||
void
|
||||
SCR_CheckDrawCenterString(void)
|
||||
{
|
||||
scr_copytop = 1;
|
||||
if (scr_center_lines > scr_erase_lines)
|
||||
scr_erase_lines = scr_center_lines;
|
||||
|
||||
scr_centertime_off -= host_frametime;
|
||||
|
||||
if (scr_centertime_off <= 0 && !cl.intermission)
|
||||
return;
|
||||
if (key_dest != key_game)
|
||||
return;
|
||||
|
||||
SCR_DrawCenterString();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
====================
|
||||
CalcFov
|
||||
====================
|
||||
*/
|
||||
float
|
||||
CalcFov(float fov_x, float width, float height)
|
||||
{
|
||||
float a;
|
||||
float x;
|
||||
|
||||
if (fov_x < 1 || fov_x > 179)
|
||||
Sys_Error("Bad fov: %f", fov_x);
|
||||
|
||||
x = width / tan(fov_x / 360 * M_PI);
|
||||
|
||||
a = atan(height / x);
|
||||
|
||||
a = a * 360 / M_PI;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SCR_CalcRefdef
|
||||
|
||||
Must be called whenever vid changes
|
||||
Internal use only
|
||||
=================
|
||||
*/
|
||||
static void
|
||||
SCR_CalcRefdef(void)
|
||||
{
|
||||
vrect_t vrect;
|
||||
float size;
|
||||
|
||||
scr_fullupdate = 0; // force a background redraw
|
||||
vid.recalc_refdef = 0;
|
||||
|
||||
// force the status bar to redraw
|
||||
Sbar_Changed();
|
||||
|
||||
//========================================
|
||||
|
||||
// bound viewsize
|
||||
if (scr_viewsize.value < 30)
|
||||
Cvar_Set("viewsize", "30");
|
||||
if (scr_viewsize.value > 120)
|
||||
Cvar_Set("viewsize", "120");
|
||||
|
||||
// bound field of view
|
||||
if (scr_fov.value < 10)
|
||||
Cvar_Set("fov", "10");
|
||||
if (scr_fov.value > 170)
|
||||
Cvar_Set("fov", "170");
|
||||
|
||||
r_refdef.fov_x = scr_fov.value;
|
||||
r_refdef.fov_y =
|
||||
CalcFov(r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
|
||||
|
||||
// intermission is always full screen
|
||||
if (cl.intermission)
|
||||
size = 120;
|
||||
else
|
||||
size = scr_viewsize.value;
|
||||
|
||||
if (size >= 120)
|
||||
sb_lines = 0; // no status bar at all
|
||||
else if (size >= 110)
|
||||
sb_lines = 24; // no inventory
|
||||
else
|
||||
sb_lines = 24 + 16 + 8;
|
||||
|
||||
// these calculations mirror those in R_Init() for r_refdef, but take no
|
||||
// account of water warping
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = vid.width;
|
||||
vrect.height = vid.height;
|
||||
|
||||
R_SetVrect(&vrect, &scr_vrect, sb_lines);
|
||||
|
||||
// guard against going from one mode to another that's less than half the
|
||||
// vertical resolution
|
||||
if (scr_con_current > vid.height)
|
||||
scr_con_current = vid.height;
|
||||
|
||||
// notify the refresh of the change
|
||||
R_ViewChanged(&vrect, sb_lines, vid.aspect);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SCR_SizeUp_f
|
||||
|
||||
Keybinding command
|
||||
=================
|
||||
*/
|
||||
void
|
||||
SCR_SizeUp_f(void)
|
||||
{
|
||||
Cvar_SetValue("viewsize", scr_viewsize.value + 10);
|
||||
vid.recalc_refdef = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SCR_SizeDown_f
|
||||
|
||||
Keybinding command
|
||||
=================
|
||||
*/
|
||||
void
|
||||
SCR_SizeDown_f(void)
|
||||
{
|
||||
Cvar_SetValue("viewsize", scr_viewsize.value - 10);
|
||||
vid.recalc_refdef = 1;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_Init
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_Init(void)
|
||||
{
|
||||
Cvar_RegisterVariable(&scr_fov);
|
||||
Cvar_RegisterVariable(&scr_viewsize);
|
||||
Cvar_RegisterVariable(&scr_conspeed);
|
||||
Cvar_RegisterVariable(&scr_showram);
|
||||
Cvar_RegisterVariable(&scr_showturtle);
|
||||
Cvar_RegisterVariable(&scr_showpause);
|
||||
Cvar_RegisterVariable(&scr_centertime);
|
||||
Cvar_RegisterVariable(&scr_printspeed);
|
||||
|
||||
//
|
||||
// register our commands
|
||||
//
|
||||
Cmd_AddCommand("screenshot", SCR_ScreenShot_f);
|
||||
Cmd_AddCommand("sizeup", SCR_SizeUp_f);
|
||||
Cmd_AddCommand("sizedown", SCR_SizeDown_f);
|
||||
|
||||
scr_ram = Draw_PicFromWad("ram");
|
||||
scr_net = Draw_PicFromWad("net");
|
||||
scr_turtle = Draw_PicFromWad("turtle");
|
||||
|
||||
scr_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_DrawRam
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawRam(void)
|
||||
{
|
||||
if (!scr_showram.value)
|
||||
return;
|
||||
|
||||
if (!r_cache_thrash)
|
||||
return;
|
||||
|
||||
Draw_Pic(scr_vrect.x + 32, scr_vrect.y, scr_ram);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_DrawTurtle
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawTurtle(void)
|
||||
{
|
||||
static int count;
|
||||
|
||||
if (!scr_showturtle.value)
|
||||
return;
|
||||
|
||||
if (host_frametime < 0.1) {
|
||||
count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
if (count < 3)
|
||||
return;
|
||||
|
||||
Draw_Pic(scr_vrect.x, scr_vrect.y, scr_turtle);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_DrawNet
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawNet(void)
|
||||
{
|
||||
if (realtime - cl.last_received_message < 0.3)
|
||||
return;
|
||||
if (cls.demoplayback)
|
||||
return;
|
||||
|
||||
Draw_Pic(scr_vrect.x + 64, scr_vrect.y, scr_net);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
DrawPause
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawPause(void)
|
||||
{
|
||||
qpic_t *pic;
|
||||
|
||||
if (!scr_showpause.value) // turn off for screenshots
|
||||
return;
|
||||
|
||||
if (!cl.paused)
|
||||
return;
|
||||
|
||||
pic = Draw_CachePic("gfx/pause.lmp");
|
||||
Draw_Pic((vid.width - pic->width) / 2,
|
||||
(vid.height - 48 - pic->height) / 2, pic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
SCR_DrawLoading
|
||||
==============
|
||||
*/
|
||||
void
|
||||
SCR_DrawLoading(void)
|
||||
{
|
||||
qpic_t *pic;
|
||||
|
||||
if (!scr_drawloading)
|
||||
return;
|
||||
|
||||
pic = Draw_CachePic("gfx/loading.lmp");
|
||||
Draw_Pic((vid.width - pic->width) / 2,
|
||||
(vid.height - 48 - pic->height) / 2, pic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_SetUpToDrawConsole
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_SetUpToDrawConsole(void)
|
||||
{
|
||||
Con_CheckResize();
|
||||
|
||||
if (scr_drawloading)
|
||||
return; // never a console with loading plaque
|
||||
|
||||
// decide on the height of the console
|
||||
con_forcedup = !cl.worldmodel || cls.state != ca_active;
|
||||
|
||||
if (con_forcedup) {
|
||||
scr_conlines = vid.height; // full screen
|
||||
scr_con_current = scr_conlines;
|
||||
} else if (key_dest == key_console)
|
||||
scr_conlines = vid.height / 2; // half screen
|
||||
else
|
||||
scr_conlines = 0; // none visible
|
||||
|
||||
if (scr_conlines < scr_con_current) {
|
||||
scr_con_current -= scr_conspeed.value * host_frametime;
|
||||
if (scr_conlines > scr_con_current)
|
||||
scr_con_current = scr_conlines;
|
||||
|
||||
} else if (scr_conlines > scr_con_current) {
|
||||
scr_con_current += scr_conspeed.value * host_frametime;
|
||||
if (scr_conlines < scr_con_current)
|
||||
scr_con_current = scr_conlines;
|
||||
}
|
||||
|
||||
if (clearconsole++ < vid.numpages) {
|
||||
scr_copytop = 1;
|
||||
Draw_TileClear(0, (int)scr_con_current, vid.width,
|
||||
vid.height - (int)scr_con_current);
|
||||
Sbar_Changed();
|
||||
} else if (clearnotify++ < vid.numpages) {
|
||||
scr_copytop = 1;
|
||||
Draw_TileClear(0, 0, vid.width, con_notifylines);
|
||||
} else
|
||||
con_notifylines = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_DrawConsole
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_DrawConsole(void)
|
||||
{
|
||||
if (scr_con_current) {
|
||||
scr_copyeverything = 1;
|
||||
Con_DrawConsole(scr_con_current);
|
||||
clearconsole = 0;
|
||||
} else {
|
||||
if (key_dest == key_game || key_dest == key_message)
|
||||
Con_DrawNotify(); // only draw notify in game
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
SCREEN SHOTS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
char manufacturer;
|
||||
char version;
|
||||
char encoding;
|
||||
char bits_per_pixel;
|
||||
unsigned short xmin, ymin, xmax, ymax;
|
||||
unsigned short hres, vres;
|
||||
unsigned char palette[48];
|
||||
char reserved;
|
||||
char color_planes;
|
||||
unsigned short bytes_per_line;
|
||||
unsigned short palette_type;
|
||||
char filler[58];
|
||||
unsigned char data; // unbounded
|
||||
} pcx_t;
|
||||
|
||||
/*
|
||||
==============
|
||||
WritePCXfile
|
||||
==============
|
||||
*/
|
||||
void
|
||||
WritePCXfile(char *filename, byte *data, int width, int height,
|
||||
int rowbytes, byte *palette)
|
||||
{
|
||||
int i, j, length;
|
||||
pcx_t *pcx;
|
||||
byte *pack;
|
||||
|
||||
pcx = Hunk_TempAlloc(width * height * 2 + 1000);
|
||||
if (pcx == NULL) {
|
||||
Con_Printf("SCR_ScreenShot_f: not enough memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pcx->manufacturer = 0x0a; // PCX id
|
||||
pcx->version = 5; // 256 color
|
||||
pcx->encoding = 1; // uncompressed
|
||||
pcx->bits_per_pixel = 8; // 256 color
|
||||
pcx->xmin = 0;
|
||||
pcx->ymin = 0;
|
||||
pcx->xmax = LittleShort((short)(width - 1));
|
||||
pcx->ymax = LittleShort((short)(height - 1));
|
||||
pcx->hres = LittleShort((short)width);
|
||||
pcx->vres = LittleShort((short)height);
|
||||
memset(pcx->palette, 0, sizeof(pcx->palette));
|
||||
pcx->color_planes = 1; // chunky image
|
||||
pcx->bytes_per_line = LittleShort((short)width);
|
||||
pcx->palette_type = LittleShort(2); // not a grey scale
|
||||
memset(pcx->filler, 0, sizeof(pcx->filler));
|
||||
|
||||
// pack the image
|
||||
pack = &pcx->data;
|
||||
|
||||
for (i = 0; i < height; i++) {
|
||||
for (j = 0; j < width; j++) {
|
||||
if ((*data & 0xc0) != 0xc0)
|
||||
*pack++ = *data++;
|
||||
else {
|
||||
*pack++ = 0xc1;
|
||||
*pack++ = *data++;
|
||||
}
|
||||
}
|
||||
|
||||
data += rowbytes - width;
|
||||
}
|
||||
|
||||
// write the palette
|
||||
*pack++ = 0x0c; // palette ID byte
|
||||
for (i = 0; i < 768; i++)
|
||||
*pack++ = *palette++;
|
||||
|
||||
// write output file
|
||||
length = pack - (byte *)pcx;
|
||||
COM_WriteFile(filename, pcx, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_ScreenShot_f
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_ScreenShot_f(void)
|
||||
{
|
||||
int i;
|
||||
char pcxname[80];
|
||||
char checkname[MAX_OSPATH];
|
||||
|
||||
//
|
||||
// find a file name to save it to
|
||||
//
|
||||
strcpy(pcxname, "quake00.pcx");
|
||||
|
||||
for (i = 0; i <= 99; i++) {
|
||||
pcxname[5] = i / 10 + '0';
|
||||
pcxname[6] = i % 10 + '0';
|
||||
sprintf(checkname, "%s/%s", com_gamedir, pcxname);
|
||||
if (Sys_FileTime(checkname) == -1)
|
||||
break; // file doesn't exist
|
||||
}
|
||||
if (i == 100) {
|
||||
Con_Printf("SCR_ScreenShot_f: Couldn't create a PCX file\n");
|
||||
return;
|
||||
}
|
||||
//
|
||||
// save the pcx file
|
||||
//
|
||||
D_EnableBackBufferAccess(); // enable direct drawing of console to back
|
||||
// buffer
|
||||
|
||||
WritePCXfile(pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes,
|
||||
host_basepal);
|
||||
|
||||
D_DisableBackBufferAccess(); // for adapters that can't stay mapped in
|
||||
// for linear writes all the time
|
||||
|
||||
Con_Printf("Wrote %s\n", pcxname);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
SCR_BeginLoadingPlaque
|
||||
|
||||
================
|
||||
*/
|
||||
void
|
||||
SCR_BeginLoadingPlaque(void)
|
||||
{
|
||||
S_StopAllSounds(true);
|
||||
|
||||
if (cls.state != ca_active)
|
||||
return;
|
||||
|
||||
// redraw with no console and the loading plaque
|
||||
Con_ClearNotify();
|
||||
scr_centertime_off = 0;
|
||||
scr_con_current = 0;
|
||||
|
||||
scr_drawloading = true;
|
||||
scr_fullupdate = 0;
|
||||
Sbar_Changed();
|
||||
SCR_UpdateScreen();
|
||||
scr_drawloading = false;
|
||||
|
||||
scr_disabled_for_loading = true;
|
||||
scr_disabled_time = realtime;
|
||||
scr_fullupdate = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SCR_EndLoadingPlaque
|
||||
|
||||
================
|
||||
*/
|
||||
void
|
||||
SCR_EndLoadingPlaque(void)
|
||||
{
|
||||
scr_disabled_for_loading = false;
|
||||
scr_fullupdate = 0;
|
||||
Con_ClearNotify();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
char *scr_notifystring;
|
||||
qboolean scr_drawdialog;
|
||||
|
||||
void
|
||||
SCR_DrawNotifyString(void)
|
||||
{
|
||||
char *start;
|
||||
int l;
|
||||
int j;
|
||||
int x, y;
|
||||
|
||||
start = scr_notifystring;
|
||||
|
||||
y = vid.height * 0.35;
|
||||
|
||||
do {
|
||||
// scan the width of the line
|
||||
for (l = 0; l < 40; l++)
|
||||
if (start[l] == '\n' || !start[l])
|
||||
break;
|
||||
x = (vid.width - l * 8) / 2;
|
||||
for (j = 0; j < l; j++, x += 8)
|
||||
Draw_Character(x, y, start[j]);
|
||||
|
||||
y += 8;
|
||||
|
||||
while (*start && *start != '\n')
|
||||
start++;
|
||||
|
||||
if (!*start)
|
||||
break;
|
||||
start++; // skip the \n
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_ModalMessage
|
||||
|
||||
Displays a text string in the center of the screen and waits for a Y or N
|
||||
keypress.
|
||||
==================
|
||||
*/
|
||||
int
|
||||
SCR_ModalMessage(char *text)
|
||||
{
|
||||
if (cls.state == ca_dedicated)
|
||||
return true;
|
||||
|
||||
scr_notifystring = text;
|
||||
|
||||
// draw a fresh screen
|
||||
scr_fullupdate = 0;
|
||||
scr_drawdialog = true;
|
||||
SCR_UpdateScreen();
|
||||
scr_drawdialog = false;
|
||||
|
||||
S_ClearBuffer(); // so dma doesn't loop current sound
|
||||
|
||||
do {
|
||||
key_count = -1; // wait for a key down and up
|
||||
Sys_SendKeyEvents();
|
||||
} while (key_lastpress != 'y' && key_lastpress != 'n'
|
||||
&& key_lastpress != K_ESCAPE);
|
||||
|
||||
scr_fullupdate = 0;
|
||||
SCR_UpdateScreen();
|
||||
|
||||
return key_lastpress == 'y';
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
===============
|
||||
SCR_BringDownConsole
|
||||
|
||||
Brings the console down and fades the palettes back to normal
|
||||
================
|
||||
*/
|
||||
void
|
||||
SCR_BringDownConsole(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
scr_centertime_off = 0;
|
||||
|
||||
for (i = 0; i < 20 && scr_conlines != scr_con_current; i++)
|
||||
SCR_UpdateScreen();
|
||||
|
||||
cl.cshifts[0].percent = 0; // no area contents palette on next frame
|
||||
VID_SetPalette(host_basepal);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_UpdateScreen
|
||||
|
||||
This is called every frame, and can also be called explicitly to flush
|
||||
text to the screen.
|
||||
|
||||
WARNING: be very careful calling this from elsewhere, because the refresh
|
||||
needs almost the entire 256k of stack space!
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_UpdateScreen(void)
|
||||
{
|
||||
static float oldscr_viewsize;
|
||||
static float oldlcd_x;
|
||||
vrect_t vrect;
|
||||
|
||||
if (scr_skipupdate || block_drawing)
|
||||
return;
|
||||
|
||||
scr_copytop = 0;
|
||||
scr_copyeverything = 0;
|
||||
|
||||
if (scr_disabled_for_loading) {
|
||||
if (realtime - scr_disabled_time > 60) {
|
||||
scr_disabled_for_loading = false;
|
||||
Con_Printf("load failed.\n");
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
if (cls.state == ca_dedicated)
|
||||
return; // stdout only
|
||||
|
||||
if (!scr_initialized || !con_initialized)
|
||||
return; // not initialized yet
|
||||
|
||||
if (scr_viewsize.value != oldscr_viewsize) {
|
||||
oldscr_viewsize = scr_viewsize.value;
|
||||
vid.recalc_refdef = 1;
|
||||
}
|
||||
//
|
||||
// check for vid changes
|
||||
//
|
||||
if (oldfov != scr_fov.value) {
|
||||
oldfov = scr_fov.value;
|
||||
vid.recalc_refdef = true;
|
||||
}
|
||||
|
||||
if (oldlcd_x != lcd_x.value) {
|
||||
oldlcd_x = lcd_x.value;
|
||||
vid.recalc_refdef = true;
|
||||
}
|
||||
|
||||
if (oldscreensize != scr_viewsize.value) {
|
||||
oldscreensize = scr_viewsize.value;
|
||||
vid.recalc_refdef = true;
|
||||
}
|
||||
|
||||
if (vid.recalc_refdef) {
|
||||
// something changed, so reorder the screen
|
||||
SCR_CalcRefdef();
|
||||
}
|
||||
//
|
||||
// do 3D refresh drawing, and then update the screen
|
||||
//
|
||||
D_EnableBackBufferAccess(); // of all overlay stuff if drawing directly
|
||||
|
||||
if (scr_fullupdate++ < vid.numpages) { // clear the entire screen
|
||||
scr_copyeverything = 1;
|
||||
Draw_TileClear(0, 0, vid.width, vid.height);
|
||||
Sbar_Changed();
|
||||
}
|
||||
|
||||
pconupdate = NULL;
|
||||
|
||||
|
||||
SCR_SetUpToDrawConsole();
|
||||
SCR_EraseCenterString();
|
||||
|
||||
D_DisableBackBufferAccess(); // for adapters that can't stay mapped in
|
||||
// for linear writes all the time
|
||||
|
||||
VID_LockBuffer();
|
||||
|
||||
V_RenderView();
|
||||
|
||||
VID_UnlockBuffer();
|
||||
|
||||
D_EnableBackBufferAccess(); // of all overlay stuff if drawing directly
|
||||
|
||||
if (scr_drawdialog) {
|
||||
Sbar_Draw();
|
||||
Draw_FadeScreen();
|
||||
SCR_DrawNotifyString();
|
||||
scr_copyeverything = true;
|
||||
} else if (scr_drawloading) {
|
||||
SCR_DrawLoading();
|
||||
Sbar_Draw();
|
||||
} else if (cl.intermission == 1 && key_dest == key_game) {
|
||||
Sbar_IntermissionOverlay();
|
||||
} else if (cl.intermission == 2 && key_dest == key_game) {
|
||||
Sbar_FinaleOverlay();
|
||||
SCR_CheckDrawCenterString();
|
||||
} else if (cl.intermission == 3 && key_dest == key_game) {
|
||||
SCR_CheckDrawCenterString();
|
||||
} else {
|
||||
SCR_DrawRam();
|
||||
SCR_DrawNet();
|
||||
SCR_DrawTurtle();
|
||||
SCR_DrawPause();
|
||||
SCR_CheckDrawCenterString();
|
||||
Sbar_Draw();
|
||||
SCR_DrawConsole();
|
||||
M_Draw();
|
||||
}
|
||||
|
||||
D_DisableBackBufferAccess(); // for adapters that can't stay mapped in
|
||||
// for linear writes all the time
|
||||
if (pconupdate) {
|
||||
D_UpdateRects(pconupdate);
|
||||
}
|
||||
|
||||
V_UpdatePalette();
|
||||
|
||||
//
|
||||
// update one of three areas
|
||||
//
|
||||
|
||||
if (scr_copyeverything) {
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = vid.width;
|
||||
vrect.height = vid.height;
|
||||
vrect.pnext = 0;
|
||||
|
||||
VID_Update(&vrect);
|
||||
} else if (scr_copytop) {
|
||||
vrect.x = 0;
|
||||
vrect.y = 0;
|
||||
vrect.width = vid.width;
|
||||
vrect.height = vid.height - sb_lines;
|
||||
vrect.pnext = 0;
|
||||
|
||||
VID_Update(&vrect);
|
||||
} else {
|
||||
vrect.x = scr_vrect.x;
|
||||
vrect.y = scr_vrect.y;
|
||||
vrect.width = scr_vrect.width;
|
||||
vrect.height = scr_vrect.height;
|
||||
vrect.pnext = 0;
|
||||
|
||||
VID_Update(&vrect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_UpdateWholeScreen
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SCR_UpdateWholeScreen(void)
|
||||
{
|
||||
scr_fullupdate = 0;
|
||||
SCR_UpdateScreen();
|
||||
}
|
244
NQ/server.h
Normal file
244
NQ/server.h
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include "progs.h"
|
||||
#include "client.h"
|
||||
|
||||
typedef enum { ss_loading, ss_active } server_state_t;
|
||||
|
||||
typedef struct {
|
||||
qboolean active; // false if only a net client
|
||||
|
||||
qboolean paused;
|
||||
qboolean loadgame; // handle connections specially
|
||||
|
||||
double time;
|
||||
|
||||
int lastcheck; // used by PF_checkclient
|
||||
double lastchecktime;
|
||||
|
||||
char name[64]; // map name
|
||||
|
||||
char modelname[64]; // maps/<name>.bsp, for model_precache[0]
|
||||
struct model_s *worldmodel;
|
||||
char *model_precache[MAX_MODELS]; // NULL terminated
|
||||
struct model_s *models[MAX_MODELS];
|
||||
char *sound_precache[MAX_SOUNDS]; // NULL terminated
|
||||
char *lightstyles[MAX_LIGHTSTYLES];
|
||||
int num_edicts;
|
||||
int max_edicts;
|
||||
edict_t *edicts; /* can NOT be array indexed, because
|
||||
edict_t is variable sized, but can
|
||||
be used to reference the world ent */
|
||||
server_state_t state; // some actions are only valid during load
|
||||
|
||||
sizebuf_t datagram;
|
||||
byte datagram_buf[MAX_DATAGRAM];
|
||||
|
||||
sizebuf_t reliable_datagram; // copied to all clients at end of frame
|
||||
byte reliable_datagram_buf[MAX_DATAGRAM];
|
||||
|
||||
sizebuf_t signon;
|
||||
byte signon_buf[8192];
|
||||
} server_t;
|
||||
|
||||
|
||||
#define NUM_PING_TIMES 16
|
||||
#define NUM_SPAWN_PARMS 16
|
||||
|
||||
typedef struct client_s {
|
||||
qboolean active; // false = client is free
|
||||
qboolean spawned; // false = don't send datagrams
|
||||
qboolean dropasap; // has been told to go to another level
|
||||
qboolean privileged; // can execute any host command
|
||||
qboolean sendsignon; // only valid before spawned
|
||||
|
||||
double last_message; // reliable messages must be sent
|
||||
// periodically
|
||||
|
||||
struct qsocket_s *netconnection; // communications handle
|
||||
|
||||
usercmd_t cmd; // movement
|
||||
vec3_t wishdir; // intended motion calced from cmd
|
||||
|
||||
sizebuf_t message; // can be added to at any time,
|
||||
// copied and clear once per frame
|
||||
byte msgbuf[MAX_MSGLEN];
|
||||
edict_t *edict; // EDICT_NUM(clientnum+1)
|
||||
char name[32]; // for printing to other people
|
||||
int colors;
|
||||
|
||||
float ping_times[NUM_PING_TIMES];
|
||||
int num_pings; // ping_times[num_pings%NUM_PING_TIMES]
|
||||
|
||||
// spawn parms are carried from level to level
|
||||
float spawn_parms[NUM_SPAWN_PARMS];
|
||||
|
||||
// client known data for deltas
|
||||
int old_frags;
|
||||
} client_t;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef struct {
|
||||
int maxclients;
|
||||
int maxclientslimit;
|
||||
struct client_s *clients; // [maxclients]
|
||||
int serverflags; // episode completion information
|
||||
qboolean changelevel_issued; // cleared when at SV_SpawnServer
|
||||
} server_static_t;
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// edict->movetype values
|
||||
#define MOVETYPE_NONE 0 // never moves
|
||||
#define MOVETYPE_ANGLENOCLIP 1
|
||||
#define MOVETYPE_ANGLECLIP 2
|
||||
#define MOVETYPE_WALK 3 // gravity
|
||||
#define MOVETYPE_STEP 4 // gravity, special edge handling
|
||||
#define MOVETYPE_FLY 5
|
||||
#define MOVETYPE_TOSS 6 // gravity
|
||||
#define MOVETYPE_PUSH 7 // no clip to world, push and crush
|
||||
#define MOVETYPE_NOCLIP 8
|
||||
#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
|
||||
#define MOVETYPE_BOUNCE 10
|
||||
|
||||
// edict->solid values
|
||||
#define SOLID_NOT 0 // no interaction with other objects
|
||||
#define SOLID_TRIGGER 1 // touch on edge, but not blocking
|
||||
#define SOLID_BBOX 2 // touch on edge, block
|
||||
#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
|
||||
#define SOLID_BSP 4 // bsp clip, touch on edge, block
|
||||
|
||||
// edict->deadflag values
|
||||
#define DEAD_NO 0
|
||||
#define DEAD_DYING 1
|
||||
#define DEAD_DEAD 2
|
||||
|
||||
#define DAMAGE_NO 0
|
||||
#define DAMAGE_YES 1
|
||||
#define DAMAGE_AIM 2
|
||||
|
||||
// edict->flags
|
||||
#define FL_FLY 1
|
||||
#define FL_SWIM 2
|
||||
//#define FL_GLIMPSE 4
|
||||
#define FL_CONVEYOR 4
|
||||
#define FL_CLIENT 8
|
||||
#define FL_INWATER 16
|
||||
#define FL_MONSTER 32
|
||||
#define FL_GODMODE 64
|
||||
#define FL_NOTARGET 128
|
||||
#define FL_ITEM 256
|
||||
#define FL_ONGROUND 512
|
||||
#define FL_PARTIALGROUND 1024 // not all corners are valid
|
||||
#define FL_WATERJUMP 2048 // player jumping out of water
|
||||
#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_MEDIUM 512
|
||||
#define SPAWNFLAG_NOT_HARD 1024
|
||||
#define SPAWNFLAG_NOT_DEATHMATCH 2048
|
||||
|
||||
//============================================================================
|
||||
|
||||
extern cvar_t teamplay;
|
||||
extern cvar_t skill;
|
||||
extern cvar_t deathmatch;
|
||||
extern cvar_t coop;
|
||||
extern cvar_t fraglimit;
|
||||
extern cvar_t timelimit;
|
||||
extern cvar_t pausable;
|
||||
|
||||
extern cvar_t sv_maxvelocity;
|
||||
extern cvar_t sv_gravity;
|
||||
extern cvar_t sv_nostep;
|
||||
extern cvar_t sv_friction;
|
||||
extern cvar_t sv_edgefriction;
|
||||
extern cvar_t sv_stopspeed;
|
||||
extern cvar_t sv_maxspeed;
|
||||
extern cvar_t sv_accelerate;
|
||||
extern cvar_t sv_idealpitchscale;
|
||||
extern cvar_t sv_aim;
|
||||
|
||||
extern server_static_t svs; // persistant server info
|
||||
extern server_t sv; // local server
|
||||
|
||||
extern client_t *host_client;
|
||||
|
||||
extern jmp_buf host_abortserver;
|
||||
|
||||
extern double host_time;
|
||||
|
||||
extern edict_t *sv_player;
|
||||
|
||||
//===========================================================
|
||||
|
||||
void SV_Init(void);
|
||||
|
||||
void SV_StartParticle(vec3_t org, vec3_t dir, int color, int count);
|
||||
void SV_StartSound(edict_t *entity, int channel, char *sample,
|
||||
int volume, float attenuation);
|
||||
|
||||
void SV_DropClient(qboolean crash);
|
||||
|
||||
void SV_SendClientMessages(void);
|
||||
void SV_ClearDatagram(void);
|
||||
|
||||
int SV_ModelIndex(char *name);
|
||||
|
||||
void SV_SetIdealPitch(void);
|
||||
|
||||
void SV_AddUpdates(void);
|
||||
|
||||
void SV_ClientThink(void);
|
||||
void SV_AddClientToServer(struct qsocket_s *ret);
|
||||
|
||||
void SV_ClientPrintf(char *fmt, ...);
|
||||
void SV_BroadcastPrintf(char *fmt, ...);
|
||||
|
||||
void SV_Physics(void);
|
||||
|
||||
qboolean SV_CheckBottom(edict_t *ent);
|
||||
qboolean SV_movestep(edict_t *ent, vec3_t move, qboolean relink);
|
||||
|
||||
void SV_WriteClientdataToMessage(edict_t *ent, sizebuf_t *msg);
|
||||
|
||||
void SV_MoveToGoal(void);
|
||||
|
||||
void SV_CheckForNewClients(void);
|
||||
void SV_RunClients(void);
|
||||
void SV_SaveSpawnparms();
|
||||
|
||||
void SV_SpawnServer(char *server);
|
||||
|
||||
#endif /* SERVER_H */
|
1165
NQ/sv_main.c
Normal file
1165
NQ/sv_main.c
Normal file
File diff suppressed because it is too large
Load Diff
407
NQ/sv_move.c
Normal file
407
NQ/sv_move.c
Normal file
@ -0,0 +1,407 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sv_move.c -- monster movement
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "progs.h"
|
||||
#include "world.h"
|
||||
#include "server.h"
|
||||
|
||||
#define STEPSIZE 18
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_CheckBottom
|
||||
|
||||
Returns false if any part of the bottom of the entity is off an edge that
|
||||
is not a staircase.
|
||||
|
||||
=============
|
||||
*/
|
||||
int c_yes, c_no;
|
||||
|
||||
qboolean
|
||||
SV_CheckBottom(edict_t *ent)
|
||||
{
|
||||
vec3_t mins, maxs, start, stop;
|
||||
trace_t trace;
|
||||
int x, y;
|
||||
float mid, bottom;
|
||||
|
||||
VectorAdd(ent->v.origin, ent->v.mins, mins);
|
||||
VectorAdd(ent->v.origin, ent->v.maxs, maxs);
|
||||
|
||||
// if all of the points under the corners are solid world, don't bother
|
||||
// with the tougher checks
|
||||
// the corners must be within 16 of the midpoint
|
||||
start[2] = mins[2] - 1;
|
||||
for (x = 0; x <= 1; x++)
|
||||
for (y = 0; y <= 1; y++) {
|
||||
start[0] = x ? maxs[0] : mins[0];
|
||||
start[1] = y ? maxs[1] : mins[1];
|
||||
if (SV_PointContents(start) != CONTENTS_SOLID)
|
||||
goto realcheck;
|
||||
}
|
||||
|
||||
c_yes++;
|
||||
return true; // we got out easy
|
||||
|
||||
realcheck:
|
||||
c_no++;
|
||||
//
|
||||
// check it for real...
|
||||
//
|
||||
start[2] = mins[2];
|
||||
|
||||
// the midpoint must be within 16 of the bottom
|
||||
start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5;
|
||||
start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5;
|
||||
stop[2] = start[2] - 2 * STEPSIZE;
|
||||
trace = SV_Move(start, vec3_origin, vec3_origin, stop, true, ent);
|
||||
|
||||
if (trace.fraction == 1.0)
|
||||
return false;
|
||||
mid = bottom = trace.endpos[2];
|
||||
|
||||
// the corners must be within 16 of the midpoint
|
||||
for (x = 0; x <= 1; x++)
|
||||
for (y = 0; y <= 1; y++) {
|
||||
start[0] = stop[0] = x ? maxs[0] : mins[0];
|
||||
start[1] = stop[1] = y ? maxs[1] : mins[1];
|
||||
|
||||
trace = SV_Move(start, vec3_origin, vec3_origin, stop, true, ent);
|
||||
|
||||
if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
|
||||
bottom = trace.endpos[2];
|
||||
if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
|
||||
return false;
|
||||
}
|
||||
|
||||
c_yes++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_movestep
|
||||
|
||||
Called by monster program code.
|
||||
The move will be adjusted for slopes and stairs, but if the move isn't
|
||||
possible, no move is done, false is returned, and
|
||||
pr_global_struct->trace_normal is set to the normal of the blocking wall
|
||||
=============
|
||||
*/
|
||||
qboolean
|
||||
SV_movestep(edict_t *ent, vec3_t move, qboolean relink)
|
||||
{
|
||||
float dz;
|
||||
vec3_t oldorg, neworg, end;
|
||||
trace_t trace;
|
||||
int i;
|
||||
edict_t *enemy;
|
||||
|
||||
// try the move
|
||||
VectorCopy(ent->v.origin, oldorg);
|
||||
VectorAdd(ent->v.origin, move, neworg);
|
||||
|
||||
// flying monsters don't step up
|
||||
if ((int)ent->v.flags & (FL_SWIM | FL_FLY)) {
|
||||
// try one move with vertical motion, then one without
|
||||
for (i = 0; i < 2; i++) {
|
||||
VectorAdd(ent->v.origin, move, neworg);
|
||||
enemy = PROG_TO_EDICT(ent->v.enemy);
|
||||
if (i == 0 && enemy != sv.edicts) {
|
||||
dz = ent->v.origin[2] -
|
||||
PROG_TO_EDICT(ent->v.enemy)->v.origin[2];
|
||||
if (dz > 40)
|
||||
neworg[2] -= 8;
|
||||
if (dz < 30)
|
||||
neworg[2] += 8;
|
||||
}
|
||||
trace =
|
||||
SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, neworg,
|
||||
false, ent);
|
||||
|
||||
if (trace.fraction == 1) {
|
||||
if (((int)ent->v.flags & FL_SWIM)
|
||||
&& SV_PointContents(trace.endpos) == CONTENTS_EMPTY)
|
||||
return false; // swim monster left water
|
||||
|
||||
VectorCopy(trace.endpos, ent->v.origin);
|
||||
if (relink)
|
||||
SV_LinkEdict(ent, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (enemy == sv.edicts)
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// push down from a step height above the wished position
|
||||
neworg[2] += STEPSIZE;
|
||||
VectorCopy(neworg, end);
|
||||
end[2] -= STEPSIZE * 2;
|
||||
|
||||
trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, false, ent);
|
||||
|
||||
if (trace.allsolid)
|
||||
return false;
|
||||
|
||||
if (trace.startsolid) {
|
||||
neworg[2] -= STEPSIZE;
|
||||
trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, false, ent);
|
||||
if (trace.allsolid || trace.startsolid)
|
||||
return false;
|
||||
}
|
||||
if (trace.fraction == 1) {
|
||||
// if monster had the ground pulled out, go ahead and fall
|
||||
if ((int)ent->v.flags & FL_PARTIALGROUND) {
|
||||
VectorAdd(ent->v.origin, move, ent->v.origin);
|
||||
if (relink)
|
||||
SV_LinkEdict(ent, true);
|
||||
ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
|
||||
// Con_Printf ("fall down\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // walked off an edge
|
||||
}
|
||||
// check point traces down for dangling corners
|
||||
VectorCopy(trace.endpos, ent->v.origin);
|
||||
|
||||
if (!SV_CheckBottom(ent)) {
|
||||
if ((int)ent->v.flags & FL_PARTIALGROUND) { // entity had floor mostly pulled out from underneath it
|
||||
// and is trying to correct
|
||||
if (relink)
|
||||
SV_LinkEdict(ent, true);
|
||||
return true;
|
||||
}
|
||||
VectorCopy(oldorg, ent->v.origin);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((int)ent->v.flags & FL_PARTIALGROUND) {
|
||||
// Con_Printf ("back on ground\n");
|
||||
ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;
|
||||
}
|
||||
ent->v.groundentity = EDICT_TO_PROG(trace.ent);
|
||||
|
||||
// the move is ok
|
||||
if (relink)
|
||||
SV_LinkEdict(ent, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
======================
|
||||
SV_StepDirection
|
||||
|
||||
Turns to the movement direction, and walks the current distance if
|
||||
facing it.
|
||||
|
||||
======================
|
||||
*/
|
||||
void PF_changeyaw(void);
|
||||
|
||||
qboolean
|
||||
SV_StepDirection(edict_t *ent, float yaw, float dist)
|
||||
{
|
||||
vec3_t move, oldorigin;
|
||||
float delta;
|
||||
|
||||
ent->v.ideal_yaw = yaw;
|
||||
PF_changeyaw();
|
||||
|
||||
yaw = yaw * M_PI * 2 / 360;
|
||||
move[0] = cos(yaw) * dist;
|
||||
move[1] = sin(yaw) * dist;
|
||||
move[2] = 0;
|
||||
|
||||
VectorCopy(ent->v.origin, oldorigin);
|
||||
if (SV_movestep(ent, move, false)) {
|
||||
delta = ent->v.angles[YAW] - ent->v.ideal_yaw;
|
||||
if (delta > 45 && delta < 315) { // not turned far enough, so don't take the step
|
||||
VectorCopy(oldorigin, ent->v.origin);
|
||||
}
|
||||
SV_LinkEdict(ent, true);
|
||||
return true;
|
||||
}
|
||||
SV_LinkEdict(ent, true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
======================
|
||||
SV_FixCheckBottom
|
||||
|
||||
======================
|
||||
*/
|
||||
void
|
||||
SV_FixCheckBottom(edict_t *ent)
|
||||
{
|
||||
// Con_Printf ("SV_FixCheckBottom\n");
|
||||
|
||||
ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SV_NewChaseDir
|
||||
|
||||
================
|
||||
*/
|
||||
#define DI_NODIR -1
|
||||
void
|
||||
SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist)
|
||||
{
|
||||
float deltax, deltay;
|
||||
float d[3];
|
||||
float tdir, olddir, turnaround;
|
||||
|
||||
olddir = anglemod((int)(actor->v.ideal_yaw / 45) * 45);
|
||||
turnaround = anglemod(olddir - 180);
|
||||
|
||||
deltax = enemy->v.origin[0] - actor->v.origin[0];
|
||||
deltay = enemy->v.origin[1] - actor->v.origin[1];
|
||||
if (deltax > 10)
|
||||
d[1] = 0;
|
||||
else if (deltax < -10)
|
||||
d[1] = 180;
|
||||
else
|
||||
d[1] = DI_NODIR;
|
||||
if (deltay < -10)
|
||||
d[2] = 270;
|
||||
else if (deltay > 10)
|
||||
d[2] = 90;
|
||||
else
|
||||
d[2] = DI_NODIR;
|
||||
|
||||
// try direct route
|
||||
if (d[1] != DI_NODIR && d[2] != DI_NODIR) {
|
||||
if (d[1] == 0)
|
||||
tdir = d[2] == 90 ? 45 : 315;
|
||||
else
|
||||
tdir = d[2] == 90 ? 135 : 215;
|
||||
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
return;
|
||||
}
|
||||
// try other directions
|
||||
if (((rand() & 3) & 1) || abs(deltay) > abs(deltax)) {
|
||||
tdir = d[1];
|
||||
d[1] = d[2];
|
||||
d[2] = tdir;
|
||||
}
|
||||
|
||||
if (d[1] != DI_NODIR && d[1] != turnaround
|
||||
&& SV_StepDirection(actor, d[1], dist))
|
||||
return;
|
||||
|
||||
if (d[2] != DI_NODIR && d[2] != turnaround
|
||||
&& SV_StepDirection(actor, d[2], dist))
|
||||
return;
|
||||
|
||||
/* there is no direct path to the player, so pick another direction */
|
||||
|
||||
if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist))
|
||||
return;
|
||||
|
||||
if (rand() & 1) { /*randomly determine direction of search */
|
||||
for (tdir = 0; tdir <= 315; tdir += 45)
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
return;
|
||||
} else {
|
||||
for (tdir = 315; tdir >= 0; tdir -= 45)
|
||||
if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
|
||||
return;
|
||||
}
|
||||
|
||||
if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist))
|
||||
return;
|
||||
|
||||
actor->v.ideal_yaw = olddir; // can't move
|
||||
|
||||
// if a bridge was pulled out from underneath a monster, it may not have
|
||||
// a valid standing position at all
|
||||
|
||||
if (!SV_CheckBottom(actor))
|
||||
SV_FixCheckBottom(actor);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
======================
|
||||
SV_CloseEnough
|
||||
|
||||
======================
|
||||
*/
|
||||
qboolean
|
||||
SV_CloseEnough(edict_t *ent, edict_t *goal, float dist)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (goal->v.absmin[i] > ent->v.absmax[i] + dist)
|
||||
return false;
|
||||
if (goal->v.absmax[i] < ent->v.absmin[i] - dist)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
======================
|
||||
SV_MoveToGoal
|
||||
|
||||
======================
|
||||
*/
|
||||
void
|
||||
SV_MoveToGoal(void)
|
||||
{
|
||||
edict_t *ent, *goal;
|
||||
float dist;
|
||||
|
||||
ent = PROG_TO_EDICT(pr_global_struct->self);
|
||||
goal = PROG_TO_EDICT(ent->v.goalentity);
|
||||
dist = G_FLOAT(OFS_PARM0);
|
||||
|
||||
if (!((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) {
|
||||
G_FLOAT(OFS_RETURN) = 0;
|
||||
return;
|
||||
}
|
||||
// if the next step hits the enemy, return immediately
|
||||
if (PROG_TO_EDICT(ent->v.enemy) != sv.edicts
|
||||
&& SV_CloseEnough(ent, goal, dist))
|
||||
return;
|
||||
|
||||
// bump around...
|
||||
if ((rand() & 3) == 1 || !SV_StepDirection(ent, ent->v.ideal_yaw, dist)) {
|
||||
SV_NewChaseDir(ent, goal, dist);
|
||||
}
|
||||
}
|
1191
NQ/sv_phys.c
Normal file
1191
NQ/sv_phys.c
Normal file
File diff suppressed because it is too large
Load Diff
630
NQ/sv_user.c
Normal file
630
NQ/sv_user.c
Normal file
@ -0,0 +1,630 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sv_user.c -- server code for moving users
|
||||
|
||||
#include "client.h"
|
||||
#include "cmd.h"
|
||||
#include "console.h"
|
||||
#include "host.h"
|
||||
#include "keys.h"
|
||||
#include "net.h"
|
||||
#include "progs.h"
|
||||
#include "protocol.h"
|
||||
#include "quakedef.h"
|
||||
#include "server.h"
|
||||
#include "sys.h"
|
||||
#include "view.h"
|
||||
#include "world.h"
|
||||
|
||||
edict_t *sv_player;
|
||||
|
||||
cvar_t sv_edgefriction = { "edgefriction", "2" };
|
||||
|
||||
static vec3_t forward, right, up;
|
||||
|
||||
vec3_t wishdir;
|
||||
float wishspeed;
|
||||
|
||||
// world
|
||||
float *angles;
|
||||
float *origin;
|
||||
float *velocity;
|
||||
|
||||
qboolean onground;
|
||||
|
||||
usercmd_t cmd;
|
||||
|
||||
cvar_t sv_idealpitchscale = { "sv_idealpitchscale", "0.8" };
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_SetIdealPitch
|
||||
===============
|
||||
*/
|
||||
#define MAX_FORWARD 6
|
||||
void
|
||||
SV_SetIdealPitch(void)
|
||||
{
|
||||
float angleval, sinval, cosval;
|
||||
trace_t tr;
|
||||
vec3_t top, bottom;
|
||||
float z[MAX_FORWARD];
|
||||
int i, j;
|
||||
int step, dir, steps;
|
||||
|
||||
if (!((int)sv_player->v.flags & FL_ONGROUND))
|
||||
return;
|
||||
|
||||
angleval = sv_player->v.angles[YAW] * M_PI * 2 / 360;
|
||||
sinval = sin(angleval);
|
||||
cosval = cos(angleval);
|
||||
|
||||
for (i = 0; i < MAX_FORWARD; i++) {
|
||||
top[0] = sv_player->v.origin[0] + cosval * (i + 3) * 12;
|
||||
top[1] = sv_player->v.origin[1] + sinval * (i + 3) * 12;
|
||||
top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2];
|
||||
|
||||
bottom[0] = top[0];
|
||||
bottom[1] = top[1];
|
||||
bottom[2] = top[2] - 160;
|
||||
|
||||
tr = SV_Move(top, vec3_origin, vec3_origin, bottom, 1, sv_player);
|
||||
if (tr.allsolid)
|
||||
return; // looking at a wall, leave ideal the way is was
|
||||
|
||||
if (tr.fraction == 1)
|
||||
return; // near a dropoff
|
||||
|
||||
z[i] = top[2] + tr.fraction * (bottom[2] - top[2]);
|
||||
}
|
||||
|
||||
dir = 0;
|
||||
steps = 0;
|
||||
for (j = 1; j < i; j++) {
|
||||
step = z[j] - z[j - 1];
|
||||
if (step > -ON_EPSILON && step < ON_EPSILON)
|
||||
continue;
|
||||
|
||||
if (dir && (step - dir > ON_EPSILON || step - dir < -ON_EPSILON))
|
||||
return; // mixed changes
|
||||
|
||||
steps++;
|
||||
dir = step;
|
||||
}
|
||||
|
||||
if (!dir) {
|
||||
sv_player->v.idealpitch = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (steps < 2)
|
||||
return;
|
||||
sv_player->v.idealpitch = -dir * sv_idealpitchscale.value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_UserFriction
|
||||
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SV_UserFriction(void)
|
||||
{
|
||||
float *vel;
|
||||
float speed, newspeed, control;
|
||||
vec3_t start, stop;
|
||||
float friction;
|
||||
trace_t trace;
|
||||
|
||||
vel = velocity;
|
||||
|
||||
speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]);
|
||||
if (!speed)
|
||||
return;
|
||||
|
||||
// if the leading edge is over a dropoff, increase friction
|
||||
start[0] = stop[0] = origin[0] + vel[0] / speed * 16;
|
||||
start[1] = stop[1] = origin[1] + vel[1] / speed * 16;
|
||||
start[2] = origin[2] + sv_player->v.mins[2];
|
||||
stop[2] = start[2] - 34;
|
||||
|
||||
trace = SV_Move(start, vec3_origin, vec3_origin, stop, true, sv_player);
|
||||
|
||||
if (trace.fraction == 1.0)
|
||||
friction = sv_friction.value * sv_edgefriction.value;
|
||||
else
|
||||
friction = sv_friction.value;
|
||||
|
||||
// apply friction
|
||||
control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
|
||||
newspeed = speed - host_frametime * control * friction;
|
||||
|
||||
if (newspeed < 0)
|
||||
newspeed = 0;
|
||||
newspeed /= speed;
|
||||
|
||||
vel[0] = vel[0] * newspeed;
|
||||
vel[1] = vel[1] * newspeed;
|
||||
vel[2] = vel[2] * newspeed;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SV_Accelerate
|
||||
==============
|
||||
*/
|
||||
cvar_t sv_maxspeed = { "sv_maxspeed", "320", false, true };
|
||||
cvar_t sv_accelerate = { "sv_accelerate", "10" };
|
||||
|
||||
#if 0
|
||||
void
|
||||
SV_Accelerate(vec3_t wishvel)
|
||||
{
|
||||
int i;
|
||||
float addspeed, accelspeed;
|
||||
vec3_t pushvec;
|
||||
|
||||
if (wishspeed == 0)
|
||||
return;
|
||||
|
||||
VectorSubtract(wishvel, velocity, pushvec);
|
||||
addspeed = VectorNormalize(pushvec);
|
||||
|
||||
accelspeed = sv_accelerate.value * host_frametime * addspeed;
|
||||
if (accelspeed > addspeed)
|
||||
accelspeed = addspeed;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
velocity[i] += accelspeed * pushvec[i];
|
||||
}
|
||||
#endif
|
||||
void
|
||||
SV_Accelerate(void)
|
||||
{
|
||||
int i;
|
||||
float addspeed, accelspeed, currentspeed;
|
||||
|
||||
currentspeed = DotProduct(velocity, wishdir);
|
||||
addspeed = wishspeed - currentspeed;
|
||||
if (addspeed <= 0)
|
||||
return;
|
||||
accelspeed = sv_accelerate.value * host_frametime * wishspeed;
|
||||
if (accelspeed > addspeed)
|
||||
accelspeed = addspeed;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
velocity[i] += accelspeed * wishdir[i];
|
||||
}
|
||||
|
||||
void
|
||||
SV_AirAccelerate(vec3_t wishveloc)
|
||||
{
|
||||
int i;
|
||||
float addspeed, wishspd, accelspeed, currentspeed;
|
||||
|
||||
wishspd = VectorNormalize(wishveloc);
|
||||
if (wishspd > 30)
|
||||
wishspd = 30;
|
||||
currentspeed = DotProduct(velocity, wishveloc);
|
||||
addspeed = wishspd - currentspeed;
|
||||
if (addspeed <= 0)
|
||||
return;
|
||||
// accelspeed = sv_accelerate.value * host_frametime;
|
||||
accelspeed = sv_accelerate.value * wishspeed * host_frametime;
|
||||
if (accelspeed > addspeed)
|
||||
accelspeed = addspeed;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
velocity[i] += accelspeed * wishveloc[i];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropPunchAngle(void)
|
||||
{
|
||||
float len;
|
||||
|
||||
len = VectorNormalize(sv_player->v.punchangle);
|
||||
|
||||
len -= 10 * host_frametime;
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
VectorScale(sv_player->v.punchangle, len, sv_player->v.punchangle);
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_WaterMove
|
||||
|
||||
===================
|
||||
*/
|
||||
void
|
||||
SV_WaterMove(void)
|
||||
{
|
||||
int i;
|
||||
vec3_t wishvel;
|
||||
float speed, newspeed, wishspeed, addspeed, accelspeed;
|
||||
|
||||
//
|
||||
// user intentions
|
||||
//
|
||||
AngleVectors(sv_player->v.v_angle, forward, right, up);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
wishvel[i] = forward[i] * cmd.forwardmove + right[i] * cmd.sidemove;
|
||||
|
||||
if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)
|
||||
wishvel[2] -= 60; // drift towards bottom
|
||||
else
|
||||
wishvel[2] += cmd.upmove;
|
||||
|
||||
wishspeed = Length(wishvel);
|
||||
if (wishspeed > sv_maxspeed.value) {
|
||||
VectorScale(wishvel, sv_maxspeed.value / wishspeed, wishvel);
|
||||
wishspeed = sv_maxspeed.value;
|
||||
}
|
||||
wishspeed *= 0.7;
|
||||
|
||||
//
|
||||
// water friction
|
||||
//
|
||||
speed = Length(velocity);
|
||||
if (speed) {
|
||||
newspeed = speed - host_frametime * speed * sv_friction.value;
|
||||
if (newspeed < 0)
|
||||
newspeed = 0;
|
||||
VectorScale(velocity, newspeed / speed, velocity);
|
||||
} else
|
||||
newspeed = 0;
|
||||
|
||||
//
|
||||
// water acceleration
|
||||
//
|
||||
if (!wishspeed)
|
||||
return;
|
||||
|
||||
addspeed = wishspeed - newspeed;
|
||||
if (addspeed <= 0)
|
||||
return;
|
||||
|
||||
VectorNormalize(wishvel);
|
||||
accelspeed = sv_accelerate.value * wishspeed * host_frametime;
|
||||
if (accelspeed > addspeed)
|
||||
accelspeed = addspeed;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
velocity[i] += accelspeed * wishvel[i];
|
||||
}
|
||||
|
||||
void
|
||||
SV_WaterJump(void)
|
||||
{
|
||||
if (sv.time > sv_player->v.teleport_time || !sv_player->v.waterlevel) {
|
||||
sv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP;
|
||||
sv_player->v.teleport_time = 0;
|
||||
}
|
||||
sv_player->v.velocity[0] = sv_player->v.movedir[0];
|
||||
sv_player->v.velocity[1] = sv_player->v.movedir[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_AirMove
|
||||
|
||||
===================
|
||||
*/
|
||||
void
|
||||
SV_AirMove(void)
|
||||
{
|
||||
int i;
|
||||
vec3_t wishvel;
|
||||
float fmove, smove;
|
||||
|
||||
AngleVectors(sv_player->v.angles, forward, right, up);
|
||||
|
||||
fmove = cmd.forwardmove;
|
||||
smove = cmd.sidemove;
|
||||
|
||||
// hack to not let you back into teleporter
|
||||
if (sv.time < sv_player->v.teleport_time && fmove < 0)
|
||||
fmove = 0;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
wishvel[i] = forward[i] * fmove + right[i] * smove;
|
||||
|
||||
if ((int)sv_player->v.movetype != MOVETYPE_WALK)
|
||||
wishvel[2] = cmd.upmove;
|
||||
else
|
||||
wishvel[2] = 0;
|
||||
|
||||
VectorCopy(wishvel, wishdir);
|
||||
wishspeed = VectorNormalize(wishdir);
|
||||
if (wishspeed > sv_maxspeed.value) {
|
||||
VectorScale(wishvel, sv_maxspeed.value / wishspeed, wishvel);
|
||||
wishspeed = sv_maxspeed.value;
|
||||
}
|
||||
|
||||
if (sv_player->v.movetype == MOVETYPE_NOCLIP) { // noclip
|
||||
VectorCopy(wishvel, velocity);
|
||||
} else if (onground) {
|
||||
SV_UserFriction();
|
||||
SV_Accelerate();
|
||||
} else { // not on ground, so little effect on velocity
|
||||
SV_AirAccelerate(wishvel);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_ClientThink
|
||||
|
||||
the move fields specify an intended velocity in pix/sec
|
||||
the angle fields specify an exact angular motion in degrees
|
||||
===================
|
||||
*/
|
||||
void
|
||||
SV_ClientThink(void)
|
||||
{
|
||||
vec3_t v_angle;
|
||||
|
||||
if (sv_player->v.movetype == MOVETYPE_NONE)
|
||||
return;
|
||||
|
||||
onground = (int)sv_player->v.flags & FL_ONGROUND;
|
||||
|
||||
origin = sv_player->v.origin;
|
||||
velocity = sv_player->v.velocity;
|
||||
|
||||
DropPunchAngle();
|
||||
|
||||
//
|
||||
// if dead, behave differently
|
||||
//
|
||||
if (sv_player->v.health <= 0)
|
||||
return;
|
||||
|
||||
//
|
||||
// angles
|
||||
// show 1/3 the pitch angle and all the roll angle
|
||||
cmd = host_client->cmd;
|
||||
angles = sv_player->v.angles;
|
||||
|
||||
VectorAdd(sv_player->v.v_angle, sv_player->v.punchangle, v_angle);
|
||||
angles[ROLL] = V_CalcRoll(sv_player->v.angles, sv_player->v.velocity) * 4;
|
||||
if (!sv_player->v.fixangle) {
|
||||
angles[PITCH] = -v_angle[PITCH] / 3;
|
||||
angles[YAW] = v_angle[YAW];
|
||||
}
|
||||
|
||||
if ((int)sv_player->v.flags & FL_WATERJUMP) {
|
||||
SV_WaterJump();
|
||||
return;
|
||||
}
|
||||
//
|
||||
// walk
|
||||
//
|
||||
if ((sv_player->v.waterlevel >= 2)
|
||||
&& (sv_player->v.movetype != MOVETYPE_NOCLIP)) {
|
||||
SV_WaterMove();
|
||||
return;
|
||||
}
|
||||
|
||||
SV_AirMove();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_ReadClientMove
|
||||
===================
|
||||
*/
|
||||
void
|
||||
SV_ReadClientMove(usercmd_t *move)
|
||||
{
|
||||
int i;
|
||||
vec3_t angle;
|
||||
int bits;
|
||||
|
||||
// read ping time
|
||||
host_client->ping_times[host_client->num_pings % NUM_PING_TIMES]
|
||||
= sv.time - MSG_ReadFloat();
|
||||
host_client->num_pings++;
|
||||
|
||||
// read current angles
|
||||
for (i = 0; i < 3; i++)
|
||||
angle[i] = MSG_ReadAngle();
|
||||
|
||||
VectorCopy(angle, host_client->edict->v.v_angle);
|
||||
|
||||
// read movement
|
||||
move->forwardmove = MSG_ReadShort();
|
||||
move->sidemove = MSG_ReadShort();
|
||||
move->upmove = MSG_ReadShort();
|
||||
|
||||
// read buttons
|
||||
bits = MSG_ReadByte();
|
||||
host_client->edict->v.button0 = bits & 1;
|
||||
host_client->edict->v.button2 = (bits & 2) >> 1;
|
||||
|
||||
i = MSG_ReadByte();
|
||||
if (i)
|
||||
host_client->edict->v.impulse = i;
|
||||
|
||||
#ifdef QUAKE2
|
||||
// read light level
|
||||
host_client->edict->v.light_level = MSG_ReadByte();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_ReadClientMessage
|
||||
|
||||
Returns false if the client should be killed
|
||||
===================
|
||||
*/
|
||||
qboolean
|
||||
SV_ReadClientMessage(void)
|
||||
{
|
||||
int ret;
|
||||
int cmd;
|
||||
char *s;
|
||||
|
||||
do {
|
||||
nextmsg:
|
||||
ret = NET_GetMessage(host_client->netconnection);
|
||||
if (ret == -1) {
|
||||
Sys_Printf("%s: NET_GetMessage failed\n", __func__);
|
||||
return false;
|
||||
}
|
||||
if (!ret)
|
||||
return true;
|
||||
|
||||
MSG_BeginReading();
|
||||
|
||||
while (1) {
|
||||
if (!host_client->active)
|
||||
return false; // a command caused an error
|
||||
|
||||
if (msg_badread) {
|
||||
Sys_Printf("%s: badread\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
cmd = MSG_ReadChar();
|
||||
|
||||
switch (cmd) {
|
||||
case -1:
|
||||
goto nextmsg; // end of message
|
||||
|
||||
default:
|
||||
Sys_Printf("%s: unknown command char\n", __func__);
|
||||
return false;
|
||||
|
||||
case clc_nop:
|
||||
//Sys_Printf ("clc_nop\n");
|
||||
break;
|
||||
|
||||
case clc_stringcmd:
|
||||
s = MSG_ReadString();
|
||||
if (host_client->privileged)
|
||||
ret = 2;
|
||||
else
|
||||
ret = 0;
|
||||
if (strncasecmp(s, "status", 6) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "god", 3) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "notarget", 8) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "fly", 3) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "name", 4) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "noclip", 6) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "say", 3) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "say_team", 8) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "tell", 4) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "color", 5) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "kill", 4) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "pause", 5) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "spawn", 5) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "begin", 5) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "prespawn", 8) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "kick", 4) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "ping", 4) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "give", 4) == 0)
|
||||
ret = 1;
|
||||
else if (strncasecmp(s, "ban", 3) == 0)
|
||||
ret = 1;
|
||||
|
||||
if (ret == 1)
|
||||
Cmd_ExecuteString(s, src_client);
|
||||
else if (ret == 2)
|
||||
Cbuf_InsertText(s);
|
||||
else
|
||||
Con_DPrintf("%s tried to %s\n", host_client->name, s);
|
||||
break;
|
||||
|
||||
case clc_disconnect:
|
||||
//Sys_Printf ("%s: client disconnected\n", __func__);
|
||||
return false;
|
||||
|
||||
case clc_move:
|
||||
SV_ReadClientMove(&host_client->cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (ret == 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_RunClients
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SV_RunClients(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0, host_client = svs.clients; i < svs.maxclients;
|
||||
i++, host_client++) {
|
||||
if (!host_client->active)
|
||||
continue;
|
||||
|
||||
sv_player = host_client->edict;
|
||||
|
||||
if (!SV_ReadClientMessage()) {
|
||||
/* client misbehaved... */
|
||||
SV_DropClient(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!host_client->spawned) {
|
||||
/* clear client movement until a new packet is received */
|
||||
memset(&host_client->cmd, 0, sizeof(host_client->cmd));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* always pause in single player if in console or menus */
|
||||
if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game))
|
||||
SV_ClientThink();
|
||||
}
|
||||
}
|
434
NQ/sys_linux.c
Normal file
434
NQ/sys_linux.c
Normal file
@ -0,0 +1,434 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "common.h"
|
||||
#include "host.h"
|
||||
#include "net_vcr.h"
|
||||
#include "quakedef.h"
|
||||
#include "sys.h"
|
||||
|
||||
qboolean isDedicated;
|
||||
|
||||
static qboolean noconinput = false;
|
||||
static qboolean nostdout = false;
|
||||
|
||||
char *basedir = ".";
|
||||
char *cachedir = "/tmp";
|
||||
|
||||
// FIXME - Used in NQ, not QW... why?
|
||||
// set for entity display
|
||||
cvar_t sys_linerefresh = { "sys_linerefresh", "0" };
|
||||
|
||||
// =======================================================================
|
||||
// General routines
|
||||
// =======================================================================
|
||||
|
||||
void
|
||||
Sys_Printf(char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[2048];
|
||||
unsigned char *p;
|
||||
int cnt;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
cnt = vsnprintf(text, sizeof(text) - 1, fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
// FIXME - require glibc >= 2.1 for C99 standard return value
|
||||
if (cnt >= sizeof(text))
|
||||
Sys_Error("memory overwrite in Sys_Printf");
|
||||
|
||||
if (nostdout)
|
||||
return;
|
||||
|
||||
// FIXME - compare with NQ + use ctype functions?
|
||||
for (p = (unsigned char *)text; *p; p++) {
|
||||
if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
|
||||
printf("[%02x]", *p);
|
||||
else
|
||||
putc(*p, stdout);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static char end1[] =
|
||||
"\x1b[?7h\x1b[40m\x1b[2J\x1b[0;1;41m\x1b[1;1H QUAKE: The Doomed Dimension \x1b[33mby \x1b[44mid\x1b[41m Software \x1b[2;1H ---------------------------------------------------------------------------- \x1b[3;1H CALL 1-800-IDGAMES TO ORDER OR FOR TECHNICAL SUPPORT \x1b[4;1H PRICE: $45.00 (PRICES MAY VARY OUTSIDE THE US.) \x1b[5;1H \x1b[6;1H \x1b[37mYes! You only have one fourth of this incredible epic. That is because most \x1b[7;1H of you have paid us nothing or at most, very little. You could steal the \x1b[8;1H game from a friend. But we both know you'll be punished by God if you do. \x1b[9;1H \x1b[33mWHY RISK ETERNAL DAMNATION? CALL 1-800-IDGAMES AND BUY NOW! \x1b[10;1H \x1b[37mRemember, we love you almost as much as He does. \x1b[11;1H \x1b[12;1H \x1b[33mProgramming: \x1b[37mJohn Carmack, Michael Abrash, John Cash \x1b[13;1H \x1b[33mDesign: \x1b[37mJohn Romero, Sandy Petersen, American McGee, Tim Willits \x1b[14;1H \x1b[33mArt: \x1b[37mAdrian Carmack, Kevin Cloud \x1b[15;1H \x1b[33mBiz: \x1b[37mJay Wilbur, Mike Wilson, Donna Jackson \x1b[16;1H \x1b[33mProjects: \x1b[37mShawn Green \x1b[33mSupport: \x1b[37mBarrett Alexander \x1b[17;1H \x1b[33mSound Effects: \x1b[37mTrent Reznor and Nine Inch Nails \x1b[18;1H For other information or details on ordering outside the US, check out the \x1b[19;1H files accompanying QUAKE or our website at http://www.idsoftware.com. \x1b[20;1H \x1b[0;41mQuake is a trademark of Id Software, inc., (c)1996 Id Software, inc. \x1b[21;1H All rights reserved. NIN logo is a registered trademark licensed to \x1b[22;1H Nothing Interactive, Inc. All rights reserved. \x1b[40m\x1b[23;1H\x1b[0m";
|
||||
static char end2[] =
|
||||
"\x1b[?7h\x1b[40m\x1b[2J\x1b[0;1;41m\x1b[1;1H QUAKE \x1b[33mby \x1b[44mid\x1b[41m Software \x1b[2;1H ----------------------------------------------------------------------------- \x1b[3;1H \x1b[37mWhy did you quit from the registered version of QUAKE? Did the \x1b[4;1H scary monsters frighten you? Or did Mr. Sandman tug at your \x1b[5;1H little lids? No matter! What is important is you love our \x1b[6;1H game, and gave us your money. Congratulations, you are probably \x1b[7;1H not a thief. \x1b[8;1H Thank You. \x1b[9;1H \x1b[33;44mid\x1b[41m Software is: \x1b[10;1H PROGRAMMING: \x1b[37mJohn Carmack, Michael Abrash, John Cash \x1b[11;1H \x1b[33mDESIGN: \x1b[37mJohn Romero, Sandy Petersen, American McGee, Tim Willits \x1b[12;1H \x1b[33mART: \x1b[37mAdrian Carmack, Kevin Cloud \x1b[13;1H \x1b[33mBIZ: \x1b[37mJay Wilbur, Mike Wilson \x1b[33mPROJECTS MAN: \x1b[37mShawn Green \x1b[14;1H \x1b[33mBIZ ASSIST: \x1b[37mDonna Jackson \x1b[33mSUPPORT: \x1b[37mBarrett Alexander \x1b[15;1H \x1b[33mSOUND EFFECTS AND MUSIC: \x1b[37mTrent Reznor and Nine Inch Nails \x1b[16;1H \x1b[17;1H If you need help running QUAKE refer to the text files in the \x1b[18;1H QUAKE directory, or our website at http://www.idsoftware.com. \x1b[19;1H If all else fails, call our technical support at 1-800-IDGAMES. \x1b[20;1H \x1b[0;41mQuake is a trademark of Id Software, inc., (c)1996 Id Software, inc. \x1b[21;1H All rights reserved. NIN logo is a registered trademark licensed \x1b[22;1H to Nothing Interactive, Inc. All rights reserved. \x1b[23;1H\x1b[40m\x1b[0m";
|
||||
|
||||
#endif
|
||||
void
|
||||
Sys_Quit(void)
|
||||
{
|
||||
Host_Shutdown();
|
||||
fcntl(STDIN_FILENO, F_SETFL,
|
||||
fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
|
||||
#if 0
|
||||
if (registered.value)
|
||||
printf("%s", end2);
|
||||
else
|
||||
printf("%s", end1);
|
||||
#endif
|
||||
fflush(stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
Sys_Init(void)
|
||||
{
|
||||
#if id386
|
||||
Sys_SetFPCW();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
Sys_Error(char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
// change stdin to non blocking
|
||||
fcntl(STDIN_FILENO, F_SETFL,
|
||||
fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
|
||||
|
||||
va_start(argptr, error);
|
||||
vsprintf(string, error, argptr);
|
||||
va_end(argptr);
|
||||
fprintf(stderr, "Error: %s\n", string);
|
||||
|
||||
Host_Shutdown();
|
||||
exit(1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Sys_FileTime
|
||||
|
||||
returns -1 if not present
|
||||
============
|
||||
*/
|
||||
int
|
||||
Sys_FileTime(const char *path)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (stat(path, &buf) == -1)
|
||||
return -1;
|
||||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Sys_mkdir(const char *path)
|
||||
{
|
||||
mkdir(path, 0777);
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileOpenRead(const char *path, int *handle)
|
||||
{
|
||||
int h;
|
||||
struct stat fileinfo;
|
||||
|
||||
|
||||
h = open(path, O_RDONLY, 0666);
|
||||
*handle = h;
|
||||
if (h == -1)
|
||||
return -1;
|
||||
|
||||
if (fstat(h, &fileinfo) == -1)
|
||||
Sys_Error("Error fstating %s", path);
|
||||
|
||||
return fileinfo.st_size;
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileOpenWrite(const char *path)
|
||||
{
|
||||
int handle;
|
||||
|
||||
umask(0);
|
||||
|
||||
handle = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
|
||||
if (handle == -1)
|
||||
Sys_Error("Error opening %s: %s", path, strerror(errno));
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileWrite(int handle, const void *src, int count)
|
||||
{
|
||||
return write(handle, src, count);
|
||||
}
|
||||
|
||||
void
|
||||
Sys_FileClose(int handle)
|
||||
{
|
||||
close(handle);
|
||||
}
|
||||
|
||||
void
|
||||
Sys_FileSeek(int handle, int position)
|
||||
{
|
||||
lseek(handle, position, SEEK_SET);
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileRead(int handle, void *dest, int count)
|
||||
{
|
||||
return read(handle, dest, count);
|
||||
}
|
||||
|
||||
void
|
||||
Sys_DebugLog(char *file, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
static char data[1024];
|
||||
int fd;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
vsprintf(data, fmt, argptr);
|
||||
va_end(argptr);
|
||||
// fd = open(file, O_WRONLY | O_BINARY | O_CREAT | O_APPEND, 0666);
|
||||
fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
|
||||
write(fd, data, strlen(data));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void
|
||||
Sys_EditFile(char *filename)
|
||||
{
|
||||
|
||||
char cmd[256];
|
||||
char *term;
|
||||
char *editor;
|
||||
|
||||
term = getenv("TERM");
|
||||
if (term && !strcmp(term, "xterm")) {
|
||||
editor = getenv("VISUAL");
|
||||
if (!editor)
|
||||
editor = getenv("EDITOR");
|
||||
if (!editor)
|
||||
editor = getenv("EDIT");
|
||||
if (!editor)
|
||||
editor = "vi";
|
||||
sprintf(cmd, "xterm -e %s %s", editor, filename);
|
||||
system(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
Sys_DoubleTime(void)
|
||||
{
|
||||
struct timeval tp;
|
||||
struct timezone tzp;
|
||||
static int secbase;
|
||||
|
||||
gettimeofday(&tp, &tzp);
|
||||
|
||||
if (!secbase) {
|
||||
secbase = tp.tv_sec;
|
||||
return tp.tv_usec / 1000000.0;
|
||||
}
|
||||
|
||||
return (tp.tv_sec - secbase) + tp.tv_usec / 1000000.0;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// Sleeps for microseconds
|
||||
// =======================================================================
|
||||
|
||||
/* FIXME - Unused only in QW? */
|
||||
static void
|
||||
Sys_LineRefresh(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
floating_point_exception_handler(int whatever)
|
||||
{
|
||||
// Sys_Warn("floating point exception\n");
|
||||
signal(SIGFPE, floating_point_exception_handler);
|
||||
}
|
||||
|
||||
// FIXME - need this at all? (see QW)
|
||||
char *
|
||||
Sys_ConsoleInput(void)
|
||||
{
|
||||
static char text[256];
|
||||
int len;
|
||||
fd_set fdset;
|
||||
struct timeval timeout;
|
||||
|
||||
if (cls.state == ca_dedicated) {
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(STDIN_FILENO, &fdset); // stdin
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout) == -1
|
||||
|| !FD_ISSET(STDIN_FILENO, &fdset))
|
||||
return NULL;
|
||||
|
||||
len = read(STDIN_FILENO, text, sizeof(text));
|
||||
if (len < 1)
|
||||
return NULL;
|
||||
text[len - 1] = 0; // rip off the /n and terminate
|
||||
|
||||
return text;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !id386
|
||||
void
|
||||
Sys_HighFPPrecision(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Sys_LowFPPrecision(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int c, char **v)
|
||||
{
|
||||
double time, oldtime, newtime;
|
||||
quakeparms_t parms;
|
||||
int j;
|
||||
|
||||
// signal(SIGFPE, floating_point_exception_handler);
|
||||
signal(SIGFPE, SIG_IGN);
|
||||
|
||||
memset(&parms, 0, sizeof(parms));
|
||||
|
||||
COM_InitArgv(c, v);
|
||||
parms.argc = com_argc;
|
||||
parms.argv = com_argv;
|
||||
|
||||
#ifdef GLQUAKE
|
||||
parms.memsize = 16 * 1024 * 1024;
|
||||
#else
|
||||
parms.memsize = 8 * 1024 * 1024;
|
||||
#endif
|
||||
|
||||
j = COM_CheckParm("-mem");
|
||||
if (j)
|
||||
parms.memsize = (int)(Q_atof(com_argv[j + 1]) * 1024 * 1024);
|
||||
parms.membase = malloc(parms.memsize);
|
||||
|
||||
parms.basedir = basedir;
|
||||
// caching is disabled by default, use -cachedir to enable
|
||||
// parms.cachedir = cachedir;
|
||||
|
||||
fcntl(STDIN_FILENO, F_SETFL,
|
||||
fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);
|
||||
|
||||
Host_Init(&parms);
|
||||
|
||||
Sys_Init();
|
||||
|
||||
if (COM_CheckParm("-nostdout"))
|
||||
nostdout = true;
|
||||
|
||||
// Make stdin non-blocking
|
||||
// FIXME - check both return values
|
||||
if (!noconinput)
|
||||
fcntl(STDIN_FILENO, F_SETFL,
|
||||
fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);
|
||||
if (!nostdout)
|
||||
printf("Tyr-Quake -- Version %s\n", stringify(TYR_VERSION));
|
||||
|
||||
oldtime = Sys_DoubleTime() - 0.1;
|
||||
while (1) {
|
||||
// find time spent rendering last frame
|
||||
newtime = Sys_DoubleTime();
|
||||
time = newtime - oldtime;
|
||||
|
||||
if (cls.state == ca_dedicated) { // play vcrfiles at max speed
|
||||
if (time < sys_ticrate.value && (vcrFile == -1 || recording)) {
|
||||
usleep(1);
|
||||
continue; // not time to run a server only tic yet
|
||||
}
|
||||
time = sys_ticrate.value;
|
||||
}
|
||||
|
||||
if (time > sys_ticrate.value * 2)
|
||||
oldtime = newtime;
|
||||
else
|
||||
oldtime += time;
|
||||
|
||||
Host_Frame(time);
|
||||
|
||||
// graphic debugging aids
|
||||
if (sys_linerefresh.value)
|
||||
Sys_LineRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_MakeCodeWriteable
|
||||
================
|
||||
*/
|
||||
void
|
||||
Sys_MakeCodeWriteable(unsigned long startaddr, unsigned long length)
|
||||
{
|
||||
int r;
|
||||
unsigned long addr;
|
||||
int psize = getpagesize();
|
||||
|
||||
addr = (startaddr & ~(psize - 1)) - psize;
|
||||
|
||||
// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
|
||||
// addr, startaddr+length, length);
|
||||
|
||||
r = mprotect((char *)addr, length + startaddr - addr + psize, 7);
|
||||
|
||||
if (r < 0)
|
||||
Sys_Error("Protection change failed");
|
||||
}
|
937
NQ/sys_win.c
Normal file
937
NQ/sys_win.c
Normal file
@ -0,0 +1,937 @@
|
||||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sys_win.c -- Win32 system interface code
|
||||
|
||||
#include <direct.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "common.h"
|
||||
#include "conproc.h"
|
||||
#include "host.h"
|
||||
#include "quakedef.h"
|
||||
#include "resource.h"
|
||||
#include "screen.h"
|
||||
#include "sys.h"
|
||||
#include "winquake.h"
|
||||
|
||||
#define MINIMUM_WIN_MEMORY 0x0C00000 /* 12 MB */
|
||||
#define MAXIMUM_WIN_MEMORY 0x2000000 /* 32 MB */
|
||||
|
||||
#define CONSOLE_ERROR_TIMEOUT 60.0 // # of seconds to wait on Sys_Error
|
||||
// running dedicated before exiting
|
||||
|
||||
#define PAUSE_SLEEP 50 // sleep time on pause or minimization
|
||||
#define NOT_FOCUS_SLEEP 20 // sleep time when not focus
|
||||
|
||||
qboolean ActiveApp;
|
||||
qboolean WinNT;
|
||||
|
||||
static double pfreq;
|
||||
static double curtime = 0.0;
|
||||
static double lastcurtime = 0.0;
|
||||
static int lowshift;
|
||||
qboolean isDedicated;
|
||||
static qboolean sc_return_on_enter = false;
|
||||
HANDLE hinput, houtput;
|
||||
|
||||
static HANDLE tevent;
|
||||
static HANDLE hFile;
|
||||
static HANDLE heventParent;
|
||||
static HANDLE heventChild;
|
||||
|
||||
void MaskExceptions(void);
|
||||
void Sys_InitFloatTime(void);
|
||||
void Sys_PushFPCW_SetHigh(void);
|
||||
void Sys_PopFPCW(void);
|
||||
|
||||
volatile int sys_checksum;
|
||||
|
||||
// TYR - debugging...
|
||||
static void printf_sys_error(DWORD err);
|
||||
|
||||
void
|
||||
Sys_DebugLog(char *file, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
static char data[1024];
|
||||
int fd;
|
||||
|
||||
va_start(argptr, fmt);
|
||||
vsprintf(data, fmt, argptr);
|
||||
va_end(argptr);
|
||||
fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
|
||||
write(fd, data, strlen(data));
|
||||
close(fd);
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_PageIn
|
||||
================
|
||||
*/
|
||||
void
|
||||
Sys_PageIn(void *ptr, int size)
|
||||
{
|
||||
byte *x;
|
||||
int m, n;
|
||||
|
||||
// touch all the memory to make sure it's there. The 16-page skip is to
|
||||
// keep Win 95 from thinking we're trying to page ourselves in (we are
|
||||
// doing that, of course, but there's no reason we shouldn't)
|
||||
x = (byte *)ptr;
|
||||
|
||||
for (n = 0; n < 4; n++) {
|
||||
for (m = 0; m < (size - 16 * 0x1000); m += 4) {
|
||||
sys_checksum += *(int *)&x[m];
|
||||
sys_checksum += *(int *)&x[m + 16 * 0x1000];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FILE IO
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#define MAX_HANDLES 10
|
||||
FILE *sys_handles[MAX_HANDLES];
|
||||
|
||||
static int
|
||||
findhandle(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < MAX_HANDLES; i++)
|
||||
if (!sys_handles[i])
|
||||
return i;
|
||||
Sys_Error("out of handles");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_filelength
|
||||
================
|
||||
*/
|
||||
int
|
||||
Sys_filelength(FILE *f)
|
||||
{
|
||||
int pos;
|
||||
int end;
|
||||
int t;
|
||||
|
||||
t = VID_ForceUnlockedAndReturnState();
|
||||
|
||||
pos = ftell(f);
|
||||
fseek(f, 0, SEEK_END);
|
||||
end = ftell(f);
|
||||
fseek(f, pos, SEEK_SET);
|
||||
|
||||
VID_ForceLockState(t);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileOpenRead(const char *path, int *hndl)
|
||||
{
|
||||
FILE *f;
|
||||
int i, retval;
|
||||
int t;
|
||||
|
||||
t = VID_ForceUnlockedAndReturnState();
|
||||
|
||||
i = findhandle();
|
||||
|
||||
f = fopen(path, "rb");
|
||||
|
||||
if (!f) {
|
||||
*hndl = -1;
|
||||
retval = -1;
|
||||
} else {
|
||||
sys_handles[i] = f;
|
||||
*hndl = i;
|
||||
retval = Sys_filelength(f);
|
||||
}
|
||||
|
||||
VID_ForceLockState(t);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileOpenWrite(const char *path)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
int t;
|
||||
|
||||
t = VID_ForceUnlockedAndReturnState();
|
||||
|
||||
i = findhandle();
|
||||
|
||||
f = fopen(path, "wb");
|
||||
if (!f)
|
||||
Sys_Error("Error opening %s: %s", path, strerror(errno));
|
||||
sys_handles[i] = f;
|
||||
|
||||
VID_ForceLockState(t);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
Sys_FileClose(int handle)
|
||||
{
|
||||
int t;
|
||||
|
||||
t = VID_ForceUnlockedAndReturnState();
|
||||
fclose(sys_handles[handle]);
|
||||
sys_handles[handle] = NULL;
|
||||
VID_ForceLockState(t);
|
||||
}
|
||||
|
||||
void
|
||||
Sys_FileSeek(int handle, int position)
|
||||
{
|
||||
int t;
|
||||
|
||||
t = VID_ForceUnlockedAndReturnState();
|
||||
fseek(sys_handles[handle], position, SEEK_SET);
|
||||
VID_ForceLockState(t);
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileRead(int handle, void *dest, int count)
|
||||
{
|
||||
int t, x;
|
||||
|
||||
t = VID_ForceUnlockedAndReturnState();
|
||||
x = fread(dest, 1, count, sys_handles[handle]);
|
||||
VID_ForceLockState(t);
|
||||
return x;
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileWrite(int handle, const void *data, int count)
|
||||
{
|
||||
int t, x;
|
||||
|
||||
t = VID_ForceUnlockedAndReturnState();
|
||||
x = fwrite(data, 1, count, sys_handles[handle]);
|
||||
VID_ForceLockState(t);
|
||||
return x;
|
||||
}
|
||||
|
||||
int
|
||||
Sys_FileTime(const char *path)
|
||||
{
|
||||
FILE *f;
|
||||
int t, retval;
|
||||
|
||||
t = VID_ForceUnlockedAndReturnState();
|
||||
|
||||
f = fopen(path, "rb");
|
||||
|
||||
if (f) {
|
||||
fclose(f);
|
||||
retval = 1;
|
||||
} else {
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
VID_ForceLockState(t);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
Sys_mkdir(const char *path)
|
||||
{
|
||||
_mkdir(path);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
SYSTEM IO
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_MakeCodeWriteable
|
||||
================
|
||||
*/
|
||||
void
|
||||
Sys_MakeCodeWriteable(unsigned long startaddr, unsigned long length)
|
||||
{
|
||||
DWORD flOldProtect;
|
||||
|
||||
if (!VirtualProtect
|
||||
((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect))
|
||||
Sys_Error("Protection change failed");
|
||||
}
|
||||
|
||||
#if !id386
|
||||
|
||||
void
|
||||
Sys_SetFPCW(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Sys_PushFPCW_SetHigh(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Sys_PopFPCW(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MaskExceptions(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Init
|
||||
================
|
||||
*/
|
||||
void
|
||||
Sys_Init(void)
|
||||
{
|
||||
LARGE_INTEGER PerformanceFreq;
|
||||
unsigned int lowpart, highpart;
|
||||
OSVERSIONINFO vinfo;
|
||||
|
||||
MaskExceptions();
|
||||
Sys_SetFPCW();
|
||||
|
||||
if (!QueryPerformanceFrequency(&PerformanceFreq))
|
||||
Sys_Error("No hardware timer available");
|
||||
|
||||
// get 32 out of the 64 time bits such that we have around
|
||||
// 1 microsecond resolution
|
||||
lowpart = (unsigned int)PerformanceFreq.LowPart;
|
||||
highpart = (unsigned int)PerformanceFreq.HighPart;
|
||||
lowshift = 0;
|
||||
|
||||
while (highpart || (lowpart > 2000000.0)) {
|
||||
lowshift++;
|
||||
lowpart >>= 1;
|
||||
lowpart |= (highpart & 1) << 31;
|
||||
highpart >>= 1;
|
||||
}
|
||||
|
||||
pfreq = 1.0 / (double)lowpart;
|
||||
|
||||
Sys_InitFloatTime();
|
||||
|
||||
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
|
||||
|
||||
if (!GetVersionEx(&vinfo))
|
||||
Sys_Error("Couldn't get OS info");
|
||||
|
||||
if ((vinfo.dwMajorVersion < 4) ||
|
||||
(vinfo.dwPlatformId == VER_PLATFORM_WIN32s)) {
|
||||
Sys_Error("Tyr-Quake requires at least Win95 or NT 4.0");
|
||||
}
|
||||
|
||||
if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||
WinNT = true;
|
||||
else
|
||||
WinNT = false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Sys_Error(char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024], text2[1024];
|
||||
char *text3 = "Press Enter to exit\n";
|
||||
char *text4 = "***********************************\n";
|
||||
char *text5 = "\n";
|
||||
DWORD dummy;
|
||||
double starttime;
|
||||
static int in_sys_error0 = 0;
|
||||
static int in_sys_error1 = 0;
|
||||
static int in_sys_error2 = 0;
|
||||
static int in_sys_error3 = 0;
|
||||
|
||||
if (!in_sys_error3) {
|
||||
in_sys_error3 = 1;
|
||||
VID_ForceUnlockedAndReturnState();
|
||||
}
|
||||
|
||||
va_start(argptr, error);
|
||||
vsprintf(text, error, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
if (isDedicated) {
|
||||
va_start(argptr, error);
|
||||
vsprintf(text, error, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
sprintf(text2, "ERROR: %s\n", text);
|
||||
WriteFile(houtput, text5, strlen(text5), &dummy, NULL);
|
||||
WriteFile(houtput, text4, strlen(text4), &dummy, NULL);
|
||||
WriteFile(houtput, text2, strlen(text2), &dummy, NULL);
|
||||
WriteFile(houtput, text3, strlen(text3), &dummy, NULL);
|
||||
WriteFile(houtput, text4, strlen(text4), &dummy, NULL);
|
||||
|
||||
starttime = Sys_DoubleTime();
|
||||
sc_return_on_enter = true; // so Enter will get us out of here
|
||||
|
||||
while (!Sys_ConsoleInput() &&
|
||||
((Sys_DoubleTime() - starttime) < CONSOLE_ERROR_TIMEOUT)) {
|
||||
}
|
||||
} else {
|
||||
// switch to windowed so the message box is visible, unless we already
|
||||
// tried that and failed
|
||||
if (!in_sys_error0) {
|
||||
in_sys_error0 = 1;
|
||||
VID_SetDefaultMode();
|
||||
MessageBox(NULL, text, "Quake Error",
|
||||
MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
|
||||
} else {
|
||||
MessageBox(NULL, text, "Double Quake Error",
|
||||
MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_sys_error1) {
|
||||
in_sys_error1 = 1;
|
||||
Host_Shutdown();
|
||||
}
|
||||
// shut down QHOST hooks if necessary
|
||||
if (!in_sys_error2) {
|
||||
in_sys_error2 = 1;
|
||||
DeinitConProc();
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
Sys_Printf(char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
DWORD dummy;
|
||||
|
||||
if (isDedicated) {
|
||||
va_start(argptr, fmt);
|
||||
vsprintf(text, fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
WriteFile(houtput, text, strlen(text), &dummy, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Sys_Quit(void)
|
||||
{
|
||||
VID_ForceUnlockedAndReturnState();
|
||||
|
||||
Host_Shutdown();
|
||||
|
||||
if (tevent)
|
||||
CloseHandle(tevent);
|
||||
|
||||
if (isDedicated)
|
||||
FreeConsole();
|
||||
|
||||
// shut down QHOST hooks if necessary
|
||||
DeinitConProc();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_DoubleTime
|
||||
================
|
||||
*/
|
||||
double
|
||||
Sys_DoubleTime(void)
|
||||
{
|
||||
static int sametimecount;
|
||||
static unsigned int oldtime;
|
||||
static int first = 1;
|
||||
LARGE_INTEGER PerformanceCount;
|
||||
unsigned int temp, t2;
|
||||
double time;
|
||||
|
||||
Sys_PushFPCW_SetHigh();
|
||||
|
||||
QueryPerformanceCounter(&PerformanceCount);
|
||||
|
||||
temp = ((unsigned int)PerformanceCount.LowPart >> lowshift) |
|
||||
((unsigned int)PerformanceCount.HighPart << (32 - lowshift));
|
||||
|
||||
if (first) {
|
||||
oldtime = temp;
|
||||
first = 0;
|
||||
} else {
|
||||
// check for turnover or backward time
|
||||
if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000)) {
|
||||
oldtime = temp; // so we can't get stuck
|
||||
} else {
|
||||
t2 = temp - oldtime;
|
||||
|
||||
time = (double)t2 *pfreq;
|
||||
|
||||
oldtime = temp;
|
||||
|
||||
curtime += time;
|
||||
|
||||
if (curtime == lastcurtime) {
|
||||
sametimecount++;
|
||||
|
||||
if (sametimecount > 100000) {
|
||||
curtime += 1.0;
|
||||
sametimecount = 0;
|
||||
}
|
||||
} else {
|
||||
sametimecount = 0;
|
||||
}
|
||||
|
||||
lastcurtime = curtime;
|
||||
}
|
||||
}
|
||||
|
||||
Sys_PopFPCW();
|
||||
|
||||
return curtime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_InitFloatTime
|
||||
================
|
||||
*/
|
||||
void
|
||||
Sys_InitFloatTime(void)
|
||||
{
|
||||
int j;
|
||||
|
||||
Sys_DoubleTime();
|
||||
|
||||
j = COM_CheckParm("-starttime");
|
||||
|
||||
if (j) {
|
||||
curtime = (double)(Q_atof(com_argv[j + 1]));
|
||||
} else {
|
||||
curtime = 0.0;
|
||||
}
|
||||
|
||||
lastcurtime = curtime;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
Sys_ConsoleInput(void)
|
||||
{
|
||||
static char text[256];
|
||||
static int len;
|
||||
INPUT_RECORD recs[1024];
|
||||
DWORD dummy;
|
||||
int ch;
|
||||
DWORD numread, numevents;
|
||||
|
||||
if (!isDedicated)
|
||||
return NULL;
|
||||
|
||||
|
||||
for (;;) {
|
||||
if (!GetNumberOfConsoleInputEvents(hinput, &numevents)) {
|
||||
DWORD err = GetLastError();
|
||||
|
||||
printf("GetNumberOfConsoleInputEvents: ");
|
||||
printf_sys_error(err);
|
||||
Sys_Error("Error getting # of console events");
|
||||
}
|
||||
|
||||
if (numevents <= 0)
|
||||
break;
|
||||
|
||||
if (!ReadConsoleInput(hinput, recs, 1, &numread))
|
||||
Sys_Error("Error reading console input");
|
||||
|
||||
if (numread != 1)
|
||||
Sys_Error("Couldn't read console input");
|
||||
|
||||
if (recs[0].EventType == KEY_EVENT) {
|
||||
if (!recs[0].Event.KeyEvent.bKeyDown) {
|
||||
ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
|
||||
|
||||
switch (ch) {
|
||||
case '\r':
|
||||
WriteFile(houtput, "\r\n", 2, &dummy, NULL);
|
||||
|
||||
if (len) {
|
||||
text[len] = 0;
|
||||
len = 0;
|
||||
return text;
|
||||
} else if (sc_return_on_enter) {
|
||||
// special case to allow exiting from the error handler on Enter
|
||||
text[0] = '\r';
|
||||
len = 0;
|
||||
return text;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
WriteFile(houtput, "\b \b", 3, &dummy, NULL);
|
||||
if (len) {
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ch >= ' ') {
|
||||
WriteFile(houtput, &ch, 1, &dummy, NULL);
|
||||
text[len] = ch;
|
||||
len = (len + 1) & 0xff;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Sys_Sleep(void)
|
||||
{
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Sys_SendKeyEvents(void)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
// we always update if there are any event, even if we're paused
|
||||
scr_skipupdate = 0;
|
||||
|
||||
if (!GetMessage(&msg, NULL, 0, 0))
|
||||
Sys_Quit();
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
WINDOWS CRAP
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
WinMain
|
||||
==================
|
||||
*/
|
||||
void
|
||||
SleepUntilInput(int time)
|
||||
{
|
||||
MsgWaitForMultipleObjects(1, &tevent, FALSE, time, QS_ALLINPUT);
|
||||
}
|
||||
|
||||
// TYR - used for debugging...
|
||||
static void
|
||||
printf_sys_error(DWORD err)
|
||||
{
|
||||
static PVOID buf;
|
||||
|
||||
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, err, 0, (LPTSTR)(&buf), 0, NULL)) {
|
||||
printf("System - %s\n", (LPTSTR)buf);
|
||||
fflush(stdout);
|
||||
LocalFree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
WinMain
|
||||
==================
|
||||
*/
|
||||
HINSTANCE global_hInstance;
|
||||
int global_nCmdShow;
|
||||
char *argv[MAX_NUM_ARGVS];
|
||||
static char *empty_string = "";
|
||||
HWND hwnd_dialog;
|
||||
|
||||
|
||||
int WINAPI
|
||||
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
{
|
||||
quakeparms_t parms;
|
||||
double time, oldtime, newtime;
|
||||
MEMORYSTATUS lpBuffer;
|
||||
static char cwd[1024];
|
||||
int t;
|
||||
RECT rect;
|
||||
DWORD err;
|
||||
|
||||
/* previous instances do not exist in Win32 */
|
||||
if (hPrevInstance)
|
||||
return 0;
|
||||
|
||||
global_hInstance = hInstance;
|
||||
global_nCmdShow = nCmdShow;
|
||||
|
||||
lpBuffer.dwLength = sizeof(MEMORYSTATUS);
|
||||
GlobalMemoryStatus(&lpBuffer);
|
||||
|
||||
if (!GetCurrentDirectory(sizeof(cwd), cwd))
|
||||
Sys_Error("Couldn't determine current directory");
|
||||
|
||||
if (cwd[strlen(cwd) - 1] == '/')
|
||||
cwd[strlen(cwd) - 1] = 0;
|
||||
|
||||
parms.basedir = cwd;
|
||||
parms.cachedir = NULL;
|
||||
|
||||
parms.argc = 1;
|
||||
argv[0] = empty_string;
|
||||
|
||||
while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS)) {
|
||||
while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
|
||||
lpCmdLine++;
|
||||
|
||||
if (*lpCmdLine) {
|
||||
argv[parms.argc] = lpCmdLine;
|
||||
parms.argc++;
|
||||
|
||||
while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
|
||||
lpCmdLine++;
|
||||
|
||||
if (*lpCmdLine) {
|
||||
*lpCmdLine = 0;
|
||||
lpCmdLine++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
parms.argv = argv;
|
||||
|
||||
COM_InitArgv(parms.argc, parms.argv);
|
||||
|
||||
parms.argc = com_argc;
|
||||
parms.argv = com_argv;
|
||||
|
||||
isDedicated = (COM_CheckParm("-dedicated") != 0);
|
||||
|
||||
if (!isDedicated) {
|
||||
hwnd_dialog =
|
||||
CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL);
|
||||
|
||||
if (hwnd_dialog) {
|
||||
if (GetWindowRect(hwnd_dialog, &rect)) {
|
||||
if (rect.left > (rect.top * 2)) {
|
||||
SetWindowPos(hwnd_dialog, 0,
|
||||
(rect.left / 2) -
|
||||
((rect.right - rect.left) / 2), rect.top, 0,
|
||||
0, SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
ShowWindow(hwnd_dialog, SW_SHOWDEFAULT);
|
||||
UpdateWindow(hwnd_dialog);
|
||||
SetForegroundWindow(hwnd_dialog);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Take the greater of all the available memory or half the total
|
||||
* memory, but at least MINIMUM_WIN_MEMORY and no more than
|
||||
* MAXIMUM_WIN_MEMORY, unless explicitly requested otherwise
|
||||
*/
|
||||
parms.memsize = lpBuffer.dwAvailPhys;
|
||||
|
||||
if (parms.memsize < MINIMUM_WIN_MEMORY)
|
||||
parms.memsize = MINIMUM_WIN_MEMORY;
|
||||
|
||||
if (parms.memsize < (lpBuffer.dwTotalPhys >> 1))
|
||||
parms.memsize = lpBuffer.dwTotalPhys >> 1;
|
||||
|
||||
if (parms.memsize > MAXIMUM_WIN_MEMORY)
|
||||
parms.memsize = MAXIMUM_WIN_MEMORY;
|
||||
|
||||
if (COM_CheckParm("-heapsize")) {
|
||||
t = COM_CheckParm("-heapsize") + 1;
|
||||
|
||||
if (t < com_argc)
|
||||
parms.memsize = Q_atoi(com_argv[t]) * 1024;
|
||||
}
|
||||
|
||||
parms.membase = malloc(parms.memsize);
|
||||
|
||||
if (!parms.membase)
|
||||
Sys_Error("Not enough memory free; check disk space");
|
||||
|
||||
Sys_PageIn(parms.membase, parms.memsize);
|
||||
|
||||
tevent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
if (!tevent)
|
||||
Sys_Error("Couldn't create event");
|
||||
|
||||
if (isDedicated) {
|
||||
if (!AllocConsole()) {
|
||||
DWORD err = GetLastError();
|
||||
|
||||
printf("AllocConsole Failed: ");
|
||||
printf_sys_error(err);
|
||||
|
||||
// Already have one? - Try free it and get a new one...
|
||||
// FIXME - Keep current console or get new one...
|
||||
FreeConsole();
|
||||
if (!AllocConsole()) {
|
||||
err = GetLastError();
|
||||
printf("AllocConsole (2nd try): Error %i\n", (int)err);
|
||||
fflush(stdout);
|
||||
|
||||
// FIXME - might not have stdout or stderr here for Sys_Error.
|
||||
Sys_Error("Couldn't create dedicated server console");
|
||||
}
|
||||
}
|
||||
// FIXME - these can fail...
|
||||
// FIXME - the whole console creation thing is pretty screwy...
|
||||
// FIXME - well, at least from cygwin rxvt it sucks...
|
||||
hinput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (!hinput) {
|
||||
err = GetLastError();
|
||||
printf("GetStdHandle(STD_INPUT_HANDLE): Error %i\n", (int)err);
|
||||
fflush(stdout);
|
||||
}
|
||||
houtput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (!hinput) {
|
||||
err = GetLastError();
|
||||
printf("GetStdHandle(STD_OUTPUT_HANDLE): Error %i\n", (int)err);
|
||||
fflush(stdout);
|
||||
}
|
||||
// give QHOST a chance to hook into the console
|
||||
// FIXME - What is QHOST?
|
||||
if ((t = COM_CheckParm("-HFILE")) > 0) {
|
||||
if (t < com_argc)
|
||||
hFile = (HANDLE)Q_atoi(com_argv[t + 1]);
|
||||
}
|
||||
|
||||
if ((t = COM_CheckParm("-HPARENT")) > 0) {
|
||||
if (t < com_argc)
|
||||
heventParent = (HANDLE)Q_atoi(com_argv[t + 1]);
|
||||
}
|
||||
|
||||
if ((t = COM_CheckParm("-HCHILD")) > 0) {
|
||||
if (t < com_argc)
|
||||
heventChild = (HANDLE)Q_atoi(com_argv[t + 1]);
|
||||
}
|
||||
|
||||
InitConProc(hFile, heventParent, heventChild);
|
||||
}
|
||||
|
||||
Sys_Init();
|
||||
|
||||
// because sound is off until we become active
|
||||
S_BlockSound();
|
||||
|
||||
Sys_Printf("Host_Init\n");
|
||||
Host_Init(&parms);
|
||||
|
||||
oldtime = Sys_DoubleTime();
|
||||
|
||||
/* main window message loop */
|
||||
while (1) {
|
||||
if (isDedicated) {
|
||||
newtime = Sys_DoubleTime();
|
||||
time = newtime - oldtime;
|
||||
|
||||
while (time < sys_ticrate.value) {
|
||||
Sys_Sleep();
|
||||
newtime = Sys_DoubleTime();
|
||||
time = newtime - oldtime;
|
||||
}
|
||||
} else {
|
||||
// yield the CPU for a little while when paused, minimized, or not the focus
|
||||
if ((cl.paused && (!ActiveApp && !DDActive)) || !window_visible()
|
||||
|| block_drawing) {
|
||||
SleepUntilInput(PAUSE_SLEEP);
|
||||
scr_skipupdate = 1; // no point in bothering to draw
|
||||
} else if (!ActiveApp && !DDActive) {
|
||||
SleepUntilInput(NOT_FOCUS_SLEEP);
|
||||
}
|
||||
|
||||
newtime = Sys_DoubleTime();
|
||||
time = newtime - oldtime;
|
||||
}
|
||||
|
||||
Host_Frame(time);
|
||||
oldtime = newtime;
|
||||
}
|
||||
|
||||
/* return success of application */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if !id386
|
||||
void
|
||||
Sys_HighFPPrecision(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Sys_LowFPPrecision(void)
|
||||
{
|
||||
}
|
||||
#endif
|
3182
NQ/vid_win.c
Normal file
3182
NQ/vid_win.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user